@@ -249,10 +249,181 @@ class Font {
249
249
250
250
return cmdContours . map ( ( commands ) => pathToPoints ( commands , options , this ) ) ;
251
251
}
252
-
253
252
/**
254
- * Test
255
- */
253
+ *
254
+ * Converts text into a 3D model that can be rendered in WebGL mode.
255
+ *
256
+ * This method transforms flat text into extruded 3D geometry, allowing
257
+ * for dynamic effects like depth, warping, and custom shading.
258
+ *
259
+ * It works by taking the outlines (contours) of each character in the
260
+ * provided text string and constructing a 3D shape from them.
261
+ *
262
+ * Once your 3D text is ready, you can rotate it in 3D space using <a href="#/p5/orbitControl">orbitControl()</a>
263
+ * — just click and drag with your mouse to see it from all angles!
264
+ *
265
+ * Use the extrude slider to give your letters depth: slide it up, and your
266
+ * flat text turns into a solid, multi-dimensional object.
267
+ *
268
+ * You can also choose from various fonts such as "Anton", "Montserrat", or "Source Serif",
269
+ * much like selecting fancy fonts in a word processor,
270
+ *
271
+ * The generated model (a Geometry object) can be manipulated further—rotated, scaled,
272
+ * or styled with shaders—to create engaging, interactive visual art.
273
+ *
274
+ * @param {String } str The text string to convert into a 3D model.
275
+ * @param {Number } x The x-coordinate for the starting position of the text.
276
+ * @param {Number } y The y-coordinate for the starting position of the text.
277
+ * @param {Number } width Maximum width of the text block (wraps text if exceeded).
278
+ * @param {Number } height Maximum height of the text block.
279
+ * @param {Object } [options] Configuration options for the 3D text:
280
+ * @param {Number } [options.extrude=0] The depth to extrude the text. A value of 0 produces
281
+ * flat text; higher values create thicker, 3D models.
282
+ * @param {Number } [options.sampleFactor=1] A factor controlling the level of detail for the text contours.
283
+ * Higher values result in smoother curves.
284
+ * @return {p5.Geometry } A geometry object representing the 3D model of the text.
285
+ *
286
+ * @example
287
+ * <div modernizr='webgl'>
288
+ * <code>
289
+ * let font;
290
+ * let geom;
291
+ *
292
+ * async function setup() {
293
+ * createCanvas(200, 200, WEBGL);
294
+ * font = await loadFont('https://fonts.gstatic.com/s/anton/v25/1Ptgg87LROyAm0K08i4gS7lu.ttf');
295
+ *
296
+ * geom = font.textToModel("Hello", 50, 0, { sampleFactor: 2 });
297
+ * geom.clearColors();
298
+ * geom.normalize();
299
+ * }
300
+ *
301
+ * function draw() {
302
+ * background(255);
303
+ * orbitControl();
304
+ * fill("red");
305
+ * strokeWeight(4);
306
+ * scale(min(width, height) / 300);
307
+ * model(geom);
308
+ * describe('A red non-extruded "Hello" in Anton on white canvas, rotatable via mouse.');
309
+ * }
310
+ * </code>
311
+ * </div>
312
+ *
313
+ * @example
314
+ * <div modernizr='webgl'>
315
+ * <code>
316
+ * let font;
317
+ * let geom;
318
+ *
319
+ * async function setup() {
320
+ * createCanvas(200, 200, WEBGL);
321
+ *
322
+ * // Alternative fonts:
323
+ * // Anton: 'https://fonts.gstatic.com/s/anton/v25/1Ptgg87LROyAm0K08i4gS7lu.ttf'
324
+ * // Montserrat: 'https://fonts.gstatic.com/s/montserrat/v29/JTUHjIg1_i6t8kCHKm4532VJOt5-QNFgpCtr6Ew-Y3tcoqK5.ttf'
325
+ * // Source Serif: 'https://fonts.gstatic.com/s/sourceserif4/v8/vEFy2_tTDB4M7-auWDN0ahZJW3IX2ih5nk3AucvUHf6OAVIJmeUDygwjihdqrhxXD-wGvjU.ttf'
326
+ *
327
+ * // Using Source Serif for this example:
328
+ * font = await loadFont('https://fonts.gstatic.com/s/sourceserif4/v8/vEFy2_tTDB4M7-auWDN0ahZJW3IX2ih5nk3AucvUHf6OAVIJmeUDygwjihdqrhxXD-wGvjU.ttf');
329
+ *
330
+ * geom = font.textToModel("Hello", 50, 0, { sampleFactor: 2, extrude: 5 });
331
+ * geom.clearColors();
332
+ * geom.normalize();
333
+ * }
334
+ *
335
+ * function draw() {
336
+ * background(255);
337
+ * orbitControl();
338
+ * fill("red");
339
+ * strokeWeight(4);
340
+ * scale(min(width, height) / 300);
341
+ * model(geom);
342
+ * describe('3D red extruded "Hello" in Source Serif on white, rotatable via mouse.');
343
+ * }
344
+ * </code>
345
+ * </div>
346
+ *
347
+ * @example
348
+ * <div modernizr='webgl'>
349
+ * <code>
350
+ * let geom;
351
+ * let activeFont;
352
+ * let artShader;
353
+ * let lineShader;
354
+ *
355
+ * // Define parameters as simple variables
356
+ * let words = 'HELLO';
357
+ * let warp = 1;
358
+ * let extrude = 5;
359
+ * let palette = ["#ffe03d", "#fe4830", "#d33033", "#6d358a", "#1c509e", "#00953c"];
360
+ *
361
+ * async function setup() {
362
+ * createCanvas(200, 200, WEBGL);
363
+ *
364
+ * // Using Anton as the default font for this example:
365
+ *
366
+ * // Alternative fonts:
367
+ * // Anton: 'https://fonts.gstatic.com/s/anton/v25/1Ptgg87LROyAm0K08i4gS7lu.ttf'
368
+ * // Montserrat: 'https://fonts.gstatic.com/s/montserrat/v29/JTUHjIg1_i6t8kCHKm4532VJOt5-QNFgpCtr6Ew-Y3tcoqK5.ttf'
369
+ * // Source Serif: 'https://fonts.gstatic.com/s/sourceserif4/v8/vEFy2_tTDB4M7-auWDN0ahZJW3IX2ih5nk3AucvUHf6OAVIJmeUDygwjihdqrhxXD-wGvjU.ttf'
370
+ * activeFont = await loadFont('https://fonts.gstatic.com/s/anton/v25/1Ptgg87LROyAm0K08i4gS7lu.ttf');
371
+ *
372
+ * geom = activeFont.textToModel(words, 0, 50, { sampleFactor: 2, extrude });
373
+ * geom.clearColors();
374
+ * geom.normalize();
375
+ *
376
+ * artShader = baseMaterialShader().modify({
377
+ * uniforms: {
378
+ * 'float time': () => millis(),
379
+ * 'float warp': () => warp,
380
+ * 'float numColors': () => palette.length,
381
+ * 'vec3[6] colors': () => palette.flatMap((c) => [red(c)/255, green(c)/255, blue(c)/255]),
382
+ * },
383
+ * vertexDeclarations: 'out vec3 vPos;',
384
+ * fragmentDeclarations: 'in vec3 vPos;',
385
+ * 'Vertex getObjectInputs': `(Vertex inputs) {
386
+ * vPos = inputs.position;
387
+ * inputs.position.x += 5. * warp * sin(inputs.position.y * 0.1 + time * 0.001) / (1. + warp);
388
+ * inputs.position.y += 5. * warp * sin(inputs.position.x * 0.1 + time * 0.0009) / (1. + warp);
389
+ * return inputs;
390
+ * }`,
391
+ * 'vec4 getFinalColor': `(vec4 _c) {
392
+ * float x = vPos.x * 0.005;
393
+ * float a = floor(fract(x) * numColors);
394
+ * float b = a == numColors - 1. ? 0. : a + 1.;
395
+ * float t = fract(x * numColors);
396
+ * vec3 c = mix(colors[int(a)], colors[int(b)], t);
397
+ * return vec4(c, 1.);
398
+ * }`
399
+ * });
400
+ *
401
+ * lineShader = baseStrokeShader().modify({
402
+ * uniforms: {
403
+ * 'float time': () => millis(),
404
+ * 'float warp': () => warp,
405
+ * },
406
+ * 'StrokeVertex getObjectInputs': `(StrokeVertex inputs) {
407
+ * inputs.position.x += 5. * warp * sin(inputs.position.y * 0.1 + time * 0.001) / (1. + warp);
408
+ * inputs.position.y += 5. * warp * sin(inputs.position.x * 0.1 + time * 0.0009) / (1. + warp);
409
+ * return inputs;
410
+ * }`,
411
+ * });
412
+ * }
413
+ *
414
+ * function draw() {
415
+ * background(255);
416
+ * orbitControl();
417
+ * shader(artShader);
418
+ * strokeShader(lineShader);
419
+ * strokeWeight(4);
420
+ * scale(min(width, height) / 210);
421
+ * model(geom);
422
+ * describe('3D wavy with different color sets "Hello" in Anton on white canvas, rotatable via mouse.');
423
+ * }
424
+ * </code>
425
+ * </div>
426
+ */
256
427
textToModel ( str , x , y , width , height , options ) {
257
428
( { width, height, options } = this . _parseArgs ( width , height , options ) ) ;
258
429
const extrude = options ?. extrude || 0 ;
0 commit comments