q5 3.7.0 → 3.7.3

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,133 @@
1
+ declare global {
2
+
3
+ // ⭐ core
4
+
5
+ /**
6
+ * Bienvenido a la documentación de q5! 🤩
7
+ *
8
+ * ¿Primera vez programando? Revisa la [guía para principiantes de q5].
9
+ *
10
+ * En estas páginas de "Aprender" puedes experimentar editando los mini ejemplos. ¡Diviértete! 😎
11
+ */
12
+
13
+ /** ⭐
14
+ * Crea un elemento de lienzo, una sección de la pantalla donde tu programa
15
+ * puede dibujar.
16
+ *
17
+ * ¡Ejecuta esta función para empezar a usar q5!
18
+ *
19
+ * Ten en cuenta que en este ejemplo, el círculo se encuentra en la posición [0, 0], el origen del lienzo.
20
+ * @param {number} [ancho] ancho del lienzo en píxeles
21
+ * @param {number} [alto] alto del lienzo en píxeles
22
+ * @param {object} [opciones] opciones para el contexto 2d
23
+ * @return {Promise<HTMLCanvasElement>} una promesa que se resuelve con el elemento canvas creado
24
+ */
25
+ function crearLienzo(ancho?: number, alto?: number, opciones: object): Promise<HTMLCanvasElement>;
26
+
27
+ /** ⭐
28
+ * Función a declarar. Se ejecutará 60 veces por segundo de forma predeterminada. Tiene comportamiento de bucle, lo que permite hacer animaciones cuadro a cuadro.
29
+ */
30
+ function dibujar(): void;
31
+
32
+ /** ⭐
33
+ * Imprime un mensaje en la consola de JavaScript. Atajo para `console.log()`.
34
+ *
35
+ * Para acceder a las herramientas del navegador (DevTools) generalmente es con click derecho + "inspeccionar", o presionando las teclas `ctrl + shift + i` o `command + option + i`. La consola se encuentra en la pestaña "console".
36
+ * @param {any} mensaje a imprimir
37
+ */
38
+ function log(...mensaje: any[]): void;
39
+
40
+ // 🧑‍🎨 shapes
41
+
42
+ /** 🧑‍🎨
43
+ * Dibuja un círculo en la posición (x, y) con el diámetro especificado.
44
+ * @param {number} x posición x del centro del círculo
45
+ * @param {number} y posición y del centro del círculo
46
+ * @param {number} diámetro del círculo
47
+ */
48
+ function círculo(): void;
49
+
50
+ // 🎨 color
51
+
52
+ /** 🎨
53
+ * Dibuja sobre todo el lienzo con un color o una imagen.
54
+ *
55
+ * Al igual que la función [`color`](https://q5js.org/learn/#color),
56
+ * esta función puede aceptar colores en una amplia gama de formatos:
57
+ * cadena de color CSS, valor de escala de grises y valores de componentes de color.
58
+ * @param {Color | Q5.Image} relleno un color o una imagen para dibujar
59
+ */
60
+ function fondo(relleno: Color | Q5.Image): void;
61
+
62
+ // 💻 display
63
+
64
+ /** 💻
65
+ * El ancho de la ventana (cantidad de píxeles). Atajo para `window.innerWidth`.
66
+ */
67
+ var anchoVentana: number;
68
+
69
+ /** 💻
70
+ * El alto de la ventana (cantidad de píxeles). Atajo para `window.innerHeight`.
71
+ */
72
+ var altoVentana: number;
73
+
74
+ /** 💻
75
+ * Número del cuadro actual, es decir, la cantidad de cuadros que se han dibujado desde que se inició el sketch.
76
+ */
77
+ var cuadroActual: number;
78
+
79
+ /** 💻
80
+ * Detiene el bucle de dibujo.
81
+ */
82
+ function pausar(): void;
83
+
84
+ /** 💻
85
+ * Dibuja el lienzo `n` veces. Si no recibe parametro, se dibuja una sola vez. Útil para controlar animaciones con el bucle pausado.
86
+ * @param {number} [n] cantidad de veces que se volverá a dibujar el lienzo, por defecto es 1
87
+ */
88
+ function redibujar(n?: number): void;
89
+
90
+ /** 💻
91
+ * Vuelve a activar el bucle de dibujo en caso de que estuviera pausado.
92
+ */
93
+ function reanudar(): void;
94
+
95
+ /** 💻
96
+ * Si recibe un parámetro, establece la cantidad ideal de cuadros que se intentarán dibujar por cada segundo (es decir, la tasa de refresco, la frecuencia del bucle).
97
+ *
98
+ * Retorna la frecuencia real alcanzada durante el último segundo de ejecución. Incluso si nunca se modifica explícitamente la frecuencia, el valor real suele fluctuar entre el ideal y 0. Para un mejor análisis del rendimiento usar las herramientas del navegador (DevTools).
99
+ * @param `hz` {number} [frecuencia] cantidad ideal de cuadros a dibujar en un segundo, por defecto es 60
100
+ * @returns {number} frecuencia real del bucle en el último segundo
101
+ */
102
+ function frecuenciaRefresco(hz: number): void | number;
103
+
104
+ /** 💻
105
+ * Retorna la cantidad ideal de cuadros que se intentan dibujar por segundo.
106
+ */
107
+ function frecuenciaIdeal(): void;
108
+
109
+ /** 💻
110
+ * Retorna la cantidad maxima de cuadros que se podrían estar dibujando en cada segundo.
111
+ *
112
+ * Es un valor teórico que depende del estado del dispositivo. Para un mejor análisis del rendimiento usar las herramientas del navegador (DevTools).
113
+ * @returns {number} cantidad máxima teorica de cuadros por segundo
114
+ */
115
+ function frecuenciaMaxima(): void;
116
+
117
+ /** 💻
118
+ * Funcion a declarar. Se ejecuta después de cada llamada a `dibujar` y de los `hooks de dibujo`, pero antes de dibujar realmente el lienzo.
119
+ *
120
+ * Útil para agregar efectos finales cuando es difícil hacerlo en la función de dibujo. Por ejemplo, al usar extensiones como p5play que dibujan capas superpuestas al lienzo.
121
+ */
122
+ function retocarDibujo(): void;
123
+
124
+ /** 💻
125
+ * Milisegundos que han pasado desde el último cuadro dibujado. Con la frecuencia por defecto a 60 hz, el tiempo aproximado es 16.6 ms o mas.
126
+ *
127
+ * Útil para mantener las animaciones sincronizadas con precisión, sobretodo si existen momentos en que la ejecución se ralentiza por sobrecarga del dispositivo. En casos en que la frecuencia real del bucle sea considerablemente mas baja, es recomendable reducir la frecuencia ideal.
128
+ */
129
+ function ultimoTiempo(): void;
130
+
131
+ }
132
+
133
+ export {};
package/defs/q5-c2d.d.ts CHANGED
@@ -21,14 +21,14 @@ declare global {
21
21
  * @param {number} [w] width or side lengths of the canvas
22
22
  * @param {number} [h] height of the canvas
23
23
  * @param {object} [opt] [options](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/getContextAttributes)
24
- * @returns {HTMLCanvasElement} created canvas element
24
+ * @returns {Promise<HTMLCanvasElement>} created canvas element
25
25
  * @example
26
26
  * // Canvas2D
27
27
  * createCanvas(200, 100);
28
28
  * background('silver');
29
29
  * circle(0, 0, 80);
30
30
  */
31
- function createCanvas(w?: number, h?: number, options?: CanvasRenderingContext2DSettings): HTMLCanvasElement;
31
+ function createCanvas(w?: number, h?: number, options?: CanvasRenderingContext2DSettings): Promise<HTMLCanvasElement>;
32
32
 
33
33
  /** ⭐
34
34
  * The q5 draw function is run 60 times per second by default.
@@ -814,6 +814,8 @@ declare global {
814
814
 
815
815
  /** 📘
816
816
  * Sets the current text style.
817
+ *
818
+ * Not applicable to WebGPU when using MSDF fonts.
817
819
  * @param {'normal' | 'italic' | 'bold' | 'bolditalic'} style font style
818
820
  * @example
819
821
  * createCanvas(200);
@@ -0,0 +1,159 @@
1
+ declare global {
2
+
3
+ // ⭐ core
4
+
5
+ /**
6
+ * Bienvenido a la documentación de q5! 🤩
7
+ *
8
+ * ¿Primera vez programando? Revisa la [guía para principiantes de q5].
9
+ *
10
+ * En estas páginas de "Aprender" puedes experimentar editando los mini ejemplos. ¡Diviértete! 😎
11
+ */
12
+
13
+ /** ⭐
14
+ * Crea un elemento de lienzo, una sección de la pantalla donde tu programa
15
+ * puede dibujar.
16
+ *
17
+ * ¡Ejecuta esta función para empezar a usar q5!
18
+ *
19
+ * Ten en cuenta que en este ejemplo, el círculo se encuentra en la posición [0, 0], el origen del lienzo.
20
+ * @param {number} [ancho] ancho del lienzo en píxeles
21
+ * @param {number} [alto] alto del lienzo en píxeles
22
+ * @param {object} [opciones] opciones para el contexto 2d
23
+ * @return {Promise<HTMLCanvasElement>} una promesa que se resuelve con el elemento canvas creado
24
+ * @example
25
+ * // WebGPU
26
+ * await crearLienzo(200, 100);
27
+ * fondo('silver');
28
+ * círculo(0, 0, 80);
29
+ */
30
+ function crearLienzo(ancho?: number, alto?: number, opciones: object): Promise<HTMLCanvasElement>;
31
+
32
+ /** ⭐
33
+ * Función a declarar. Se ejecutará 60 veces por segundo de forma predeterminada. Tiene comportamiento de bucle, lo que permite hacer animaciones cuadro a cuadro.
34
+ * @example
35
+ * q5.dibujar = function () {
36
+ * fondo('silver');
37
+ * círculo(mouseX, mouseY, 80);
38
+ * };
39
+ */
40
+ function dibujar(): void;
41
+
42
+ /** ⭐
43
+ * Imprime un mensaje en la consola de JavaScript. Atajo para `console.log()`.
44
+ *
45
+ * Para acceder a las herramientas del navegador (DevTools) generalmente es con click derecho + "inspeccionar", o presionando las teclas `ctrl + shift + i` o `command + option + i`. La consola se encuentra en la pestaña "console".
46
+ * @param {any} mensaje a imprimir
47
+ * @example
48
+ * q5.dibujar = function () {
49
+ * círculo(mouseX, mouseY, 80);
50
+ * log('The mouse is at:', mouseX, mouseY);
51
+ * };
52
+ */
53
+ function log(...mensaje: any[]): void;
54
+
55
+ // 🧑‍🎨 shapes
56
+
57
+ /** 🧑‍🎨
58
+ * Dibuja un círculo en la posición (x, y) con el diámetro especificado.
59
+ * @param {number} x posición x del centro del círculo
60
+ * @param {number} y posición y del centro del círculo
61
+ * @param {number} diámetro del círculo
62
+ * @example
63
+ * await crearLienzo(200, 100);
64
+ * círculo(0, 0, 80);
65
+ */
66
+ function círculo(): void;
67
+
68
+ // 🎨 color
69
+
70
+ /** 🎨
71
+ * Dibuja sobre todo el lienzo con un color o una imagen.
72
+ *
73
+ * Al igual que la función [`color`](https://q5js.org/learn/#color),
74
+ * esta función puede aceptar colores en una amplia gama de formatos:
75
+ * cadena de color CSS, valor de escala de grises y valores de componentes de color.
76
+ * @param {Color | Q5.Image} relleno un color o una imagen para dibujar
77
+ * @example
78
+ * await crearLienzo(200, 100);
79
+ * fondo('crimson');
80
+ * @example
81
+ * q5.dibujar = function () {
82
+ * fondo(0.5, 0.2);
83
+ * círculo(mouseX, mouseY, 20);
84
+ * };
85
+ */
86
+ function fondo(relleno: Color | Q5.Image): void;
87
+
88
+ // 💻 display
89
+
90
+ /** 💻
91
+ * El ancho de la ventana (cantidad de píxeles). Atajo para `window.innerWidth`.
92
+ */
93
+ var anchoVentana: number;
94
+
95
+ /** 💻
96
+ * El alto de la ventana (cantidad de píxeles). Atajo para `window.innerHeight`.
97
+ */
98
+ var altoVentana: number;
99
+
100
+ /** 💻
101
+ * Número del cuadro actual, es decir, la cantidad de cuadros que se han dibujado desde que se inició el sketch.
102
+ */
103
+ var cuadroActual: number;
104
+
105
+ /** 💻
106
+ * Detiene el bucle de dibujo.
107
+ */
108
+ function pausar(): void;
109
+
110
+ /** 💻
111
+ * Dibuja el lienzo `n` veces. Si no recibe parametro, se dibuja una sola vez. Útil para controlar animaciones con el bucle pausado.
112
+ * @param {number} [n] cantidad de veces que se volverá a dibujar el lienzo, por defecto es 1
113
+ */
114
+ function redibujar(n?: number): void;
115
+
116
+ /** 💻
117
+ * Vuelve a activar el bucle de dibujo en caso de que estuviera pausado.
118
+ */
119
+ function reanudar(): void;
120
+
121
+ /** 💻
122
+ * Si recibe un parámetro, establece la cantidad ideal de cuadros que se intentarán dibujar por cada segundo (es decir, la tasa de refresco, la frecuencia del bucle).
123
+ *
124
+ * Retorna la frecuencia real alcanzada durante el último segundo de ejecución. Incluso si nunca se modifica explícitamente la frecuencia, el valor real suele fluctuar entre el ideal y 0. Para un mejor análisis del rendimiento usar las herramientas del navegador (DevTools).
125
+ * @param `hz` {number} [frecuencia] cantidad ideal de cuadros a dibujar en un segundo, por defecto es 60
126
+ * @returns {number} frecuencia real del bucle en el último segundo
127
+ */
128
+ function frecuenciaRefresco(hz: number): void | number;
129
+
130
+ /** 💻
131
+ * Retorna la cantidad ideal de cuadros que se intentan dibujar por segundo.
132
+ */
133
+ function frecuenciaIdeal(): void;
134
+
135
+ /** 💻
136
+ * Retorna la cantidad maxima de cuadros que se podrían estar dibujando en cada segundo.
137
+ *
138
+ * Es un valor teórico que depende del estado del dispositivo. Para un mejor análisis del rendimiento usar las herramientas del navegador (DevTools).
139
+ * @returns {number} cantidad máxima teorica de cuadros por segundo
140
+ */
141
+ function frecuenciaMaxima(): void;
142
+
143
+ /** 💻
144
+ * Funcion a declarar. Se ejecuta después de cada llamada a `dibujar` y de los `hooks de dibujo`, pero antes de dibujar realmente el lienzo.
145
+ *
146
+ * Útil para agregar efectos finales cuando es difícil hacerlo en la función de dibujo. Por ejemplo, al usar extensiones como p5play que dibujan capas superpuestas al lienzo.
147
+ */
148
+ function retocarDibujo(): void;
149
+
150
+ /** 💻
151
+ * Milisegundos que han pasado desde el último cuadro dibujado. Con la frecuencia por defecto a 60 hz, el tiempo aproximado es 16.6 ms o mas.
152
+ *
153
+ * Útil para mantener las animaciones sincronizadas con precisión, sobretodo si existen momentos en que la ejecución se ralentiza por sobrecarga del dispositivo. En casos en que la frecuencia real del bucle sea considerablemente mas baja, es recomendable reducir la frecuencia ideal.
154
+ */
155
+ function ultimoTiempo(): void;
156
+
157
+ }
158
+
159
+ export {};
package/deno.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@q5/q5",
3
- "version": "3.7.0",
3
+ "version": "3.7.3",
4
4
  "license": "LGPL-3.0",
5
5
  "description": "Beginner friendly graphics powered by WebGPU and optimized for interactive art!",
6
6
  "author": "quinton-ashley",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "q5",
3
- "version": "3.7.0",
3
+ "version": "3.7.3",
4
4
  "description": "Beginner friendly graphics powered by WebGPU and optimized for interactive art!",
5
5
  "author": "quinton-ashley",
6
6
  "contributors": [
@@ -29,7 +29,7 @@
29
29
  }
30
30
  ],
31
31
  "scripts": {
32
- "bundle": "cat src/q5-core.js src/q5-canvas.js src/q5-c2d-canvas.js src/q5-c2d-shapes.js src/q5-c2d-image.js src/q5-c2d-soft-filters.js src/q5-c2d-text.js src/q5-color.js src/q5-display.js src/q5-dom.js src/q5-fes.js src/q5-input.js src/q5-math.js src/q5-record.js src/q5-sound.js src/q5-util.js src/q5-vector.js src/q5-webgpu.js > q5.js",
32
+ "bundle": "cat src/q5-core.js src/q5-canvas.js src/q5-c2d-canvas.js src/q5-c2d-shapes.js src/q5-c2d-image.js src/q5-c2d-soft-filters.js src/q5-c2d-text.js src/q5-color.js src/q5-display.js src/q5-dom.js src/q5-fes.js src/q5-input.js src/q5-math.js src/q5-record.js src/q5-sound.js src/q5-util.js src/q5-vector.js src/q5-webgpu.js src/q5-lang.js > q5.js",
33
33
  "min": "terser q5.js --compress ecma=2025 --mangle > q5.min.js",
34
34
  "dist": "bun bundle && bun min",
35
35
  "dist-p5play": "bun dist && cp q5.js ../../web/p5play-web/v3/q5.js && cp q5.min.js ../../web/p5play-web/v3/q5.min.js",
package/q5.d.ts CHANGED
@@ -21,14 +21,14 @@ declare global {
21
21
  * @param {number} [w] width or side lengths of the canvas
22
22
  * @param {number} [h] height of the canvas
23
23
  * @param {object} [opt] [options](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/getContextAttributes)
24
- * @returns {HTMLCanvasElement} created canvas element
24
+ * @returns {Promise<HTMLCanvasElement>} created canvas element
25
25
  * @example
26
26
  * // Canvas2D
27
27
  * createCanvas(200, 100);
28
28
  * background('silver');
29
29
  * circle(0, 0, 80);
30
30
  */
31
- function createCanvas(w?: number, h?: number, options?: CanvasRenderingContext2DSettings): HTMLCanvasElement;
31
+ function createCanvas(w?: number, h?: number, options?: CanvasRenderingContext2DSettings): Promise<HTMLCanvasElement>;
32
32
 
33
33
  /** ⭐
34
34
  * The q5 draw function is run 60 times per second by default.
@@ -814,6 +814,8 @@ declare global {
814
814
 
815
815
  /** 📘
816
816
  * Sets the current text style.
817
+ *
818
+ * Not applicable to WebGPU when using MSDF fonts.
817
819
  * @param {'normal' | 'italic' | 'bold' | 'bolditalic'} style font style
818
820
  * @example
819
821
  * createCanvas(200);
package/q5.js CHANGED
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * q5.js
3
- * @version 3.6
3
+ * @version 3.7
4
4
  * @author quinton-ashley
5
5
  * @contributors evanalulu, Tezumie, ormaq, Dukemz, LingDong-
6
6
  * @license LGPL-3.0
@@ -275,32 +275,13 @@ function Q5(scope, parent, renderer) {
275
275
 
276
276
  let t = globalScope || $;
277
277
 
278
- let userFns = [
279
- 'postProcess',
280
- 'mouseMoved',
281
- 'mousePressed',
282
- 'mouseReleased',
283
- 'mouseDragged',
284
- 'mouseClicked',
285
- 'doubleClicked',
286
- 'mouseWheel',
287
- 'keyPressed',
288
- 'keyReleased',
289
- 'keyTyped',
290
- 'touchStarted',
291
- 'touchMoved',
292
- 'touchEnded',
293
- 'windowResized',
294
- 'preload'
295
- ];
278
+ let userFns = Q5._userFns.slice(0, 15);
296
279
  // shim if undefined
297
280
  for (let name of userFns) $[name] ??= () => {};
298
281
 
299
- userFns.pop();
300
-
301
- let allUserFns = ['update', 'draw', 'drawFrame', ...userFns];
302
-
303
282
  if ($._isGlobal) {
283
+ let allUserFns = Q5._userFns.slice(0, 17);
284
+
304
285
  for (let name of allUserFns) {
305
286
  if (Q5[name]) $[name] = Q5[name];
306
287
  else {
@@ -314,6 +295,9 @@ function Q5(scope, parent, renderer) {
314
295
 
315
296
  function wrapWithFES(name) {
316
297
  const fn = t[name] || $[name];
298
+ if (fn == undefined) {
299
+ log('hi');
300
+ }
317
301
  $[name] = (event) => {
318
302
  try {
319
303
  return fn(event);
@@ -329,8 +313,10 @@ function Q5(scope, parent, renderer) {
329
313
 
330
314
  readyResolve();
331
315
 
332
- wrapWithFES('preload');
333
- $.preload();
316
+ if ($.preload) {
317
+ wrapWithFES('preload');
318
+ $.preload();
319
+ }
334
320
 
335
321
  // wait for the user to define setup, update, or draw
336
322
  await Promise.race([
@@ -400,6 +386,26 @@ Q5._friendlyError = (msg, func) => {
400
386
  };
401
387
  Q5._validateParameters = () => true;
402
388
 
389
+ Q5._userFns = [
390
+ 'postProcess',
391
+ 'mouseMoved',
392
+ 'mousePressed',
393
+ 'mouseReleased',
394
+ 'mouseDragged',
395
+ 'mouseClicked',
396
+ 'doubleClicked',
397
+ 'mouseWheel',
398
+ 'keyPressed',
399
+ 'keyReleased',
400
+ 'keyTyped',
401
+ 'touchStarted',
402
+ 'touchMoved',
403
+ 'touchEnded',
404
+ 'windowResized',
405
+ 'update',
406
+ 'draw'
407
+ ];
408
+
403
409
  Q5.hooks = {
404
410
  init: [],
405
411
  presetup: [],
@@ -459,7 +465,7 @@ if (typeof window == 'object') {
459
465
  window.WEBGPU = 'webgpu';
460
466
  } else global.window = 0;
461
467
 
462
- Q5.version = Q5.VERSION = '3.6';
468
+ Q5.version = Q5.VERSION = '3.7';
463
469
 
464
470
  if (typeof document == 'object') {
465
471
  document.addEventListener('DOMContentLoaded', () => {
@@ -6857,6 +6863,8 @@ fn fragMain(f: FragParams) -> @location(0) vec4f {
6857
6863
  if (_rectMode == 'corner') {
6858
6864
  x += hw;
6859
6865
  y += hh;
6866
+ hw = Math.abs(hw);
6867
+ hh = Math.abs(hh);
6860
6868
  } else if (_rectMode == 'radius') {
6861
6869
  hw = w;
6862
6870
  hh = h;
@@ -8050,6 +8058,7 @@ fn fragMain(f : FragParams) -> @location(0) vec4f {
8050
8058
  };
8051
8059
 
8052
8060
  $.textSize = (size) => {
8061
+ if (!$._font) $._g.textSize(size);
8053
8062
  if (size == undefined) return _textSize;
8054
8063
  _textSize = size;
8055
8064
  if (!leadingSet) {
@@ -8086,6 +8095,8 @@ fn fragMain(f : FragParams) -> @location(0) vec4f {
8086
8095
  };
8087
8096
 
8088
8097
  $.textLeading = (lineHeight) => {
8098
+ if (!$._font) return $._g.textLeading(lineHeight);
8099
+ if (!lineHeight) return leading;
8089
8100
  $._font.lineHeight = leading = lineHeight;
8090
8101
  leadDiff = leading - _textSize;
8091
8102
  leadPercent = leading / _textSize;
@@ -8097,6 +8108,10 @@ fn fragMain(f : FragParams) -> @location(0) vec4f {
8097
8108
  if (vert) _textBaseline = vert;
8098
8109
  };
8099
8110
 
8111
+ $.textStyle = (style) => {
8112
+ // stub
8113
+ };
8114
+
8100
8115
  let charStack = [],
8101
8116
  textStack = [];
8102
8117
 
@@ -8174,6 +8189,8 @@ fn fragMain(f : FragParams) -> @location(0) vec4f {
8174
8189
  return $.textImage(img, x, y);
8175
8190
  }
8176
8191
 
8192
+ let hasNewline;
8193
+
8177
8194
  if (str.length > w) {
8178
8195
  let wrapped = [];
8179
8196
  let i = 0;
@@ -8189,21 +8206,10 @@ fn fragMain(f : FragParams) -> @location(0) vec4f {
8189
8206
  i = end + 1;
8190
8207
  }
8191
8208
  str = wrapped.join('\n');
8209
+ hasNewline = true;
8192
8210
  }
8193
8211
 
8194
- let spaces = 0, // whitespace char count, not literal spaces
8195
- hasNewline;
8196
- for (let i = 0; i < str.length; i++) {
8197
- let c = str[i];
8198
- switch (c) {
8199
- case '\n':
8200
- hasNewline = true;
8201
- case '\r':
8202
- case '\t':
8203
- case ' ':
8204
- spaces++;
8205
- }
8206
- }
8212
+ hasNewline ??= str.includes('\n');
8207
8213
 
8208
8214
  let charsData = [];
8209
8215
 
@@ -8226,7 +8232,7 @@ fn fragMain(f : FragParams) -> @location(0) vec4f {
8226
8232
  else if (tb == 'center') y -= _textSize * 0.5;
8227
8233
  else if (tb == 'bottom') y -= leading;
8228
8234
  } else {
8229
- // measure the text to get the line widths before setting
8235
+ // measure the text to get the line height before setting
8230
8236
  // the x position to properly align the text
8231
8237
  measurements = measureText($._font, str);
8232
8238
 
@@ -8269,8 +8275,27 @@ fn fragMain(f : FragParams) -> @location(0) vec4f {
8269
8275
  };
8270
8276
 
8271
8277
  $.textWidth = (str) => {
8272
- if (!$._font) return 0;
8273
- return measureText($._font, str).width;
8278
+ if (!$._font) {
8279
+ $._g.textSize(_textSize);
8280
+ return $._g.textWidth(str);
8281
+ }
8282
+ return (measureText($._font, str).width * _textSize) / 42;
8283
+ };
8284
+
8285
+ $.textAscent = (str) => {
8286
+ if (!$._font) {
8287
+ $._g.textSize(_textSize);
8288
+ return $._g.textAscent(str);
8289
+ }
8290
+ return leading - leadDiff;
8291
+ };
8292
+
8293
+ $.textDescent = (str) => {
8294
+ if (!$._font) {
8295
+ $._g.textSize(_textSize);
8296
+ return $._g.textDescent(str);
8297
+ }
8298
+ return leadDiff;
8274
8299
  };
8275
8300
 
8276
8301
  $.createTextImage = (str, w, h) => {
@@ -8443,3 +8468,106 @@ Q5.WebGPU = async function (scope, parent) {
8443
8468
  await q.ready;
8444
8469
  return q;
8445
8470
  };
8471
+ const libLangs = `
8472
+ # core
8473
+ createCanvas -> es:crearLienzo ja:キャンバスを作成する
8474
+
8475
+ # color
8476
+ background -> es:fondo ja:背景
8477
+
8478
+ # display
8479
+ windowWidth -> es:anchoVentana
8480
+ windowHeight -> es:altoVentana
8481
+ frameCount -> es:cuadroActual
8482
+ noLoop -> es:pausar
8483
+ redraw -> es:redibujar
8484
+ loop -> es:reanudar
8485
+ frameRate -> es:frecuenciaRefresco
8486
+ getTargetFrameRate -> es:frecuenciaIdeal
8487
+ getFPS -> es:frecuenciaMaxima
8488
+ deltaTime -> es:ultimoTiempo
8489
+
8490
+ # shape
8491
+ circle -> es:círculo
8492
+ `;
8493
+
8494
+ const userLangs = `
8495
+ update -> es:actualizar
8496
+ draw -> es:dibujar
8497
+ postProcess -> es:retocarDibujo
8498
+ `;
8499
+
8500
+ const parseLangs = function (data, lang) {
8501
+ let map = {};
8502
+ for (let l of data.split('\n')) {
8503
+ let i = l.indexOf(' ' + lang + ':');
8504
+ if (i > 0 && l[0] != '#') {
8505
+ map[l.split(' ')[0]] = l.slice(i + 4).split(' ')[0];
8506
+ }
8507
+ }
8508
+ return map;
8509
+ };
8510
+
8511
+ Object.defineProperty(Q5, 'lang', {
8512
+ get: () => Q5._lang || 'en',
8513
+ set: (val) => {
8514
+ if (val == Q5._lang) return;
8515
+
8516
+ Q5._lang = val;
8517
+
8518
+ if (val == 'en') {
8519
+ // reset to English only user functions
8520
+ Q5._userFns = Q5._userFns.slice(0, 17);
8521
+ Q5._libMap = Q5._userFnsMap = {};
8522
+ return;
8523
+ }
8524
+
8525
+ let libMap = parseLangs(libLangs, val);
8526
+
8527
+ if (typeof window == 'object') {
8528
+ window[libMap.createCanvas] = createCanvas;
8529
+ }
8530
+
8531
+ let userFnsMap = parseLangs(userLangs, val);
8532
+
8533
+ for (let name in userFnsMap) {
8534
+ let translatedName = userFnsMap[name];
8535
+ if (Q5.hasOwnProperty(translatedName)) continue;
8536
+ Object.defineProperty(Q5, translatedName, {
8537
+ get: () => Q5[name],
8538
+ set: (fn) => (Q5[name] = fn)
8539
+ });
8540
+ }
8541
+
8542
+ Q5._libMap = libMap;
8543
+ Q5._userFnsMap = userFnsMap;
8544
+ Q5._userFns.push(...Object.values(userFnsMap));
8545
+ }
8546
+ });
8547
+
8548
+ Q5.modules.lang = ($) => {
8549
+ let userFnsMap = Q5._userFnsMap;
8550
+
8551
+ for (let name in userFnsMap) {
8552
+ let translatedName = userFnsMap[name];
8553
+ Object.defineProperty($, translatedName, {
8554
+ get: () => $[name],
8555
+ set: (fn) => ($[name] = fn)
8556
+ });
8557
+ }
8558
+
8559
+ let libMap = Q5._libMap;
8560
+
8561
+ if (libMap?.createCanvas) {
8562
+ $[libMap.createCanvas] = $.createCanvas;
8563
+ }
8564
+ };
8565
+
8566
+ Q5.addHook('presetup', ($) => {
8567
+ let libMap = Q5._libMap;
8568
+
8569
+ for (let name in libMap) {
8570
+ let translatedName = libMap[name];
8571
+ $[translatedName] = $[name];
8572
+ }
8573
+ });