Skip to content

textmode.js / ShapeAssemblyMode

Enumeration: ShapeAssemblyMode

Shape assembly modes for Textmodifier.beginShape.

Enumeration Members

Enumeration MemberValueDescription
LINE_LOOP3Draw consecutive vertices as one connected closed loop. Use this for orbit rings, cells, seals, and procedural outlines where the last vertex should connect back to the first. Example /** * @title Textmodifier.LINE_LOOP */ const t = textmode.create({ width: window.innerWidth, height: window.innerHeight, fontSize: 16, }); const mode = t.LINE_LOOP; const modeName = 'LINE_LOOP'; const labelLayer = t.layers.add(); function drawText(text, x, y, r = 220, g = 230, b = 255) { t.push(); t.printAlign('left', 'top'); t.charColor(r, g, b); t.print(text, x, y); t.pop(); } t.draw(() => { const time = t.frameCount * 0.035; t.background(7, 10, 24); t.lineWeight(0.7); t.beginShape(mode); for (let i = 0; i < 64; i++) { const p = i / 64; const a = p * Math.PI * 2; const r = 10 + Math.sin(a * 5 + time * 2) * 2 + Math.cos(a * 3 - time) * 1.5; t.char(i % 5 === 0 ? '#' : '+'); t.charColor(120 + Math.sin(a) * 80, 210, 180 + Math.cos(a) * 60); t.vertex(Math.cos(a) * r, Math.sin(a) * r); } t.endShape(); }); labelLayer.draw(() => { t.clear(); const left = -Math.floor(t.grid.cols / 2); const top = -Math.floor(t.grid.rows / 2); let y = top + 3; const x = left + 3; drawText('TEXTMODIFIER.LINE_LOOP', x, y++, 100, 255, 140); drawText('------------------------------------', x, y++, 80, 100, 150); drawText('CONCEPT: CLOSED OUTLINE', x, y++, 100, 220, 255); drawText('Last vertex returns to first.', x, y++, 140, 160, 190); drawText('Good for orbiting contours.', x, y++, 140, 160, 190); drawText('------------------------------------', x, y++, 80, 100, 150); drawText(MODE: ${modeName}, x, y++, 140, 255, 180); }); t.windowResized(() => { t.resizeCanvas(window.innerWidth, window.innerHeight); });
LINE_STRIP2Draw consecutive vertices as one connected open path. Use this for trails, contours, oscillators, and continuous generative paths that should not automatically close. Example /** * @title Textmodifier.LINE_STRIP */ const t = textmode.create({ width: window.innerWidth, height: window.innerHeight, fontSize: 16, }); const mode = t.LINE_STRIP; const modeName = 'LINE_STRIP'; const labelLayer = t.layers.add(); function drawText(text, x, y, r = 220, g = 230, b = 255) { t.push(); t.printAlign('left', 'top'); t.charColor(r, g, b); t.print(text, x, y); t.pop(); } t.draw(() => { const time = t.frameCount * 0.04; t.background(5, 12, 25); t.lineWeight(0.8); t.beginShape(mode); for (let i = 0; i < 70; i++) { const p = i / 69; const x = -22 + p * 44; const y = Math.sin(p * Math.PI * 6 + time * 2) * 5 + Math.sin(p * 19 - time) * 2; t.char(i % 4 === 0 ? '@' : '~'); t.charColor(80 + p * 160, 170 + Math.sin(p * 7) * 70, 255); t.vertex(x, y); } t.endShape(); }); labelLayer.draw(() => { t.clear(); const left = -Math.floor(t.grid.cols / 2); const top = -Math.floor(t.grid.rows / 2); let y = top + 3; const x = left + 3; drawText('TEXTMODIFIER.LINE_STRIP', x, y++, 100, 255, 140); drawText('------------------------------------', x, y++, 80, 100, 150); drawText('CONCEPT: OPEN CONTINUOUS PATH', x, y++, 100, 220, 255); drawText('Consecutive vertices connect.', x, y++, 140, 160, 190); drawText('The ends remain open.', x, y++, 140, 160, 190); drawText('------------------------------------', x, y++, 80, 100, 150); drawText(MODE: ${modeName}, x, y++, 140, 255, 180); }); t.windowResized(() => { t.resizeCanvas(window.innerWidth, window.innerHeight); });
LINES1Draw each pair of recorded vertices as an independent line segment. Use this for disconnected strokes, hatching, radial spokes, and other geometry where every two vertices form a separate edge. Example /** * @title Textmodifier.LINES */ const t = textmode.create({ width: window.innerWidth, height: window.innerHeight, fontSize: 16, }); const mode = t.LINES; const modeName = 'LINES'; const labelLayer = t.layers.add(); function drawText(text, x, y, r = 220, g = 230, b = 255) { t.push(); t.printAlign('left', 'top'); t.charColor(r, g, b); t.print(text, x, y); t.pop(); } t.draw(() => { const time = t.frameCount * 0.035; t.background(8, 8, 22); t.lineWeight(0.7); t.beginShape(mode); for (let i = 0; i < 30; i++) { const a = i * 12 + t.frameCount * 0.9; const r1 = 4 + Math.sin(time + i) * 2; const r2 = 13 + Math.cos(time * 1.7 + i) * 3; t.char(i % 2 ? '/' : '\\'); t.charColor(120 + i * 4, 240 - i * 3, 210); t.vertex(Math.cos(a) * r1, Math.sin(a) * r1); t.vertex(Math.cos(a + 30) * r2, Math.sin(a + 30) * r2); } t.endShape(); }); labelLayer.draw(() => { t.clear(); const left = -Math.floor(t.grid.cols / 2); const top = -Math.floor(t.grid.rows / 2); let y = top + 3; const x = left + 3; drawText('TEXTMODIFIER.LINES', x, y++, 100, 255, 140); drawText('------------------------------------', x, y++, 80, 100, 150); drawText('CONCEPT: PAIRED SEGMENTS', x, y++, 100, 220, 255); drawText('Every two vertices connect.', x, y++, 140, 160, 190); drawText('Each pair stays separate.', x, y++, 140, 160, 190); drawText('------------------------------------', x, y++, 80, 100, 150); drawText(MODE: ${modeName}, x, y++, 140, 255, 180); }); t.windowResized(() => { t.resizeCanvas(window.innerWidth, window.innerHeight); });
POINTS0Draw each recorded vertex as a separate point. Use this for particle fields, sampled paths, and other custom shapes where every vertex is an independent mark. Example /** * @title Textmodifier.POINTS */ const t = textmode.create({ width: window.innerWidth, height: window.innerHeight, fontSize: 16, }); const mode = t.POINTS; const modeName = 'POINTS'; const labelLayer = t.layers.add(); function drawText(text, x, y, r = 220, g = 230, b = 255) { t.push(); t.printAlign('left', 'top'); t.charColor(r, g, b); t.print(text, x, y); t.pop(); } t.draw(() => { const time = t.frameCount * 0.035; t.background(6, 10, 24); t.beginShape(mode); for (let i = 0; i < 96; i++) { const a = i * 13.7 + t.frameCount * 1.4; const r = 2 + i * 0.12 + Math.sin(time * 2 + i) * 1.2; t.char(i % 3 === 0 ? '*' : '.'); t.charColor(90 + i, 180 + Math.sin(i) * 50, 255); t.cellColor(4, 12 + (i % 6) * 5, 30); t.vertex(Math.cos(a) * r, Math.sin(a) * r); } t.endShape(); }); labelLayer.draw(() => { t.clear(); const left = -Math.floor(t.grid.cols / 2); const top = -Math.floor(t.grid.rows / 2); let y = top + 3; const x = left + 3; drawText('TEXTMODIFIER.POINTS', x, y++, 100, 255, 140); drawText('------------------------------------', x, y++, 80, 100, 150); drawText('CONCEPT: VERTEX PARTICLES', x, y++, 100, 220, 255); drawText('Each vertex becomes a point.', x, y++, 140, 160, 190); drawText('No edges connect the marks.', x, y++, 140, 160, 190); drawText('------------------------------------', x, y++, 80, 100, 150); drawText(MODE: ${modeName}, x, y++, 140, 255, 180); }); t.windowResized(() => { t.resizeCanvas(window.innerWidth, window.innerHeight); });
QUAD_STRIP8Draw paired vertices as a connected strip of quads. Use this for woven bands, thick paths, and flexible ribbons where each pair of vertices extends the next four-sided segment. Example /** * @title Textmodifier.QUAD_STRIP */ const t = textmode.create({ width: window.innerWidth, height: window.innerHeight, fontSize: 16, }); const mode = t.QUAD_STRIP; const modeName = 'QUAD_STRIP'; const labelLayer = t.layers.add(); function drawText(text, x, y, r = 220, g = 230, b = 255) { t.push(); t.printAlign('left', 'top'); t.charColor(r, g, b); t.print(text, x, y); t.pop(); } t.draw(() => { const time = t.frameCount * 0.04; t.background(8, 8, 24); t.beginShape(mode); for (let i = 0; i < 28; i++) { const p = i / 27; const x = -20 + p * 40; const y = Math.sin(p * Math.PI * 4 + time * 2) * 5; const width = 2 + Math.cos(time + i) * 0.8; t.char(i % 2 ? '=' : '#'); t.charColor(255 - p * 80, 140 + p * 90, 210); t.cellColor(40 + p * 30, 16, 45 + p * 40); t.vertex(x, y - width); t.vertex(x, y + width); } t.endShape(); }); labelLayer.draw(() => { t.clear(); const left = -Math.floor(t.grid.cols / 2); const top = -Math.floor(t.grid.rows / 2); let y = top + 3; const x = left + 3; drawText('TEXTMODIFIER.QUAD_STRIP', x, y++, 100, 255, 140); drawText('------------------------------------', x, y++, 80, 100, 150); drawText('CONCEPT: CONNECTED QUAD BAND', x, y++, 100, 220, 255); drawText('Each pair extends the strip.', x, y++, 140, 160, 190); drawText('Good for thick flowing paths.', x, y++, 140, 160, 190); drawText('------------------------------------', x, y++, 80, 100, 150); drawText(MODE: ${modeName}, x, y++, 140, 255, 180); }); t.windowResized(() => { t.resizeCanvas(window.innerWidth, window.innerHeight); });
QUADS7Draw each group of four vertices as a quad split into two triangles. Use this for tiled panels, procedural cells, and blocky surfaces where every four vertices define a separate four-sided patch. Example /** * @title Textmodifier.QUADS */ const t = textmode.create({ width: window.innerWidth, height: window.innerHeight, fontSize: 16, }); const mode = t.QUADS; const modeName = 'QUADS'; const labelLayer = t.layers.add(); function drawText(text, x, y, r = 220, g = 230, b = 255) { t.push(); t.printAlign('left', 'top'); t.charColor(r, g, b); t.print(text, x, y); t.pop(); } t.draw(() => { const time = t.frameCount * 0.04; t.background(6, 10, 20); t.beginShape(mode); for (let gy = -2; gy <= 2; gy++) { for (let gx = -4; gx <= 4; gx++) { const cx = gx * 4 + Math.sin(time + gy) * 1.5; const cy = gy * 4 + Math.cos(time + gx) * 1.5; const s = 1.4 + Math.sin(time * 2 + gx + gy) * 0.5; t.char((gx + gy) % 2 ? '#' : '+'); t.charColor(120 + gx * 14, 190 + gy * 12, 250); t.cellColor(12 + gx * 3, 22 + gy * 6, 45); t.vertex(cx - s, cy - s); t.vertex(cx + s, cy - s); t.vertex(cx + s, cy + s); t.vertex(cx - s, cy + s); } } t.endShape(); }); labelLayer.draw(() => { t.clear(); const left = -Math.floor(t.grid.cols / 2); const top = -Math.floor(t.grid.rows / 2); let y = top + 3; const x = left + 3; drawText('TEXTMODIFIER.QUADS', x, y++, 100, 255, 140); drawText('------------------------------------', x, y++, 80, 100, 150); drawText('CONCEPT: FOUR VERTEX PATCHES', x, y++, 100, 220, 255); drawText('Every four vertices fill.', x, y++, 140, 160, 190); drawText('Each cell is independent.', x, y++, 140, 160, 190); drawText('------------------------------------', x, y++, 80, 100, 150); drawText(MODE: ${modeName}, x, y++, 140, 255, 180); }); t.windowResized(() => { t.resizeCanvas(window.innerWidth, window.innerHeight); });
TRIANGLE_FAN6Draw triangles that all share the first recorded vertex. Use this for fans, wedges, circular bursts, and filled radial forms expanding from a shared center. Example /** * @title Textmodifier.TRIANGLE_FAN */ const t = textmode.create({ width: window.innerWidth, height: window.innerHeight, fontSize: 16, }); const mode = t.TRIANGLE_FAN; const modeName = 'TRIANGLE_FAN'; const labelLayer = t.layers.add(); function drawText(text, x, y, r = 220, g = 230, b = 255) { t.push(); t.printAlign('left', 'top'); t.charColor(r, g, b); t.print(text, x, y); t.pop(); } t.draw(() => { const time = t.frameCount * 0.035; t.background(10, 8, 24); t.beginShape(mode); t.char('@'); t.charColor(255, 245, 180); t.cellColor(65, 40, 20); t.vertex(0, 0); for (let i = 0; i <= 48; i++) { const p = i / 48; const a = p * Math.PI * 2 + time; const r = 12 + Math.sin(a * 6 - time * 3) * 2; t.char(i % 3 ? '*' : '#'); t.charColor(255, 130 + Math.sin(a) * 70, 90 + Math.cos(a) * 60); t.cellColor(55 + Math.sin(a) * 20, 18, 12); t.vertex(Math.cos(a) * r, Math.sin(a) * r); } t.endShape(); }); labelLayer.draw(() => { t.clear(); const left = -Math.floor(t.grid.cols / 2); const top = -Math.floor(t.grid.rows / 2); let y = top + 3; const x = left + 3; drawText('TEXTMODIFIER.TRIANGLE_FAN', x, y++, 100, 255, 140); drawText('------------------------------------', x, y++, 80, 100, 150); drawText('CONCEPT: SHARED CENTER', x, y++, 100, 220, 255); drawText('Every triangle uses vertex 1.', x, y++, 140, 160, 190); drawText('Great for radial bursts.', x, y++, 140, 160, 190); drawText('------------------------------------', x, y++, 80, 100, 150); drawText(MODE: ${modeName}, x, y++, 140, 255, 180); }); t.windowResized(() => { t.resizeCanvas(window.innerWidth, window.innerHeight); });
TRIANGLE_STRIP5Draw overlapping triplets of vertices as a connected triangle strip. Use this for ribbons, folded bands, and efficient connected surfaces built from a single alternating vertex sequence. Example /** * @title Textmodifier.TRIANGLE_STRIP */ const t = textmode.create({ width: window.innerWidth, height: window.innerHeight, fontSize: 16, }); const mode = t.TRIANGLE_STRIP; const modeName = 'TRIANGLE_STRIP'; const labelLayer = t.layers.add(); function drawText(text, x, y, r = 220, g = 230, b = 255) { t.push(); t.printAlign('left', 'top'); t.charColor(r, g, b); t.print(text, x, y); t.pop(); } t.draw(() => { const time = t.frameCount * 0.04; t.background(5, 12, 26); t.beginShape(mode); for (let i = 0; i < 42; i++) { const p = i / 41; const x = -20 + p * 40; const wave = Math.sin(p * Math.PI * 5 + time * 2) * 4; const side = i % 2 === 0 ? -2.5 : 2.5; t.char(i % 2 === 0 ? '/' : '\\'); t.charColor(100 + p * 120, 240 - p * 70, 255); t.cellColor(8, 28 + p * 40, 45 + p * 70); t.vertex(x, wave + side); } t.endShape(); }); labelLayer.draw(() => { t.clear(); const left = -Math.floor(t.grid.cols / 2); const top = -Math.floor(t.grid.rows / 2); let y = top + 3; const x = left + 3; drawText('TEXTMODIFIER.TRIANGLE_STRIP', x, y++, 100, 255, 140); drawText('------------------------------------', x, y++, 80, 100, 150); drawText('CONCEPT: CONNECTED RIBBON', x, y++, 100, 220, 255); drawText('Each new vertex adds a face.', x, y++, 140, 160, 190); drawText('Alternating sides make width.', x, y++, 140, 160, 190); drawText('------------------------------------', x, y++, 80, 100, 150); drawText(MODE: ${modeName}, x, y++, 140, 255, 180); }); t.windowResized(() => { t.resizeCanvas(window.innerWidth, window.innerHeight); });
TRIANGLES4Draw each group of three vertices as an independent triangle. Use this for faceted fields, low-poly shards, and filled geometry where each triangle controls its own three corners. Example /** * @title Textmodifier.TRIANGLES */ const t = textmode.create({ width: window.innerWidth, height: window.innerHeight, fontSize: 16, }); const mode = t.TRIANGLES; const modeName = 'TRIANGLES'; const labelLayer = t.layers.add(); function drawText(text, x, y, r = 220, g = 230, b = 255) { t.push(); t.printAlign('left', 'top'); t.charColor(r, g, b); t.print(text, x, y); t.pop(); } t.draw(() => { const time = t.frameCount * 0.035; t.background(8, 8, 20); t.beginShape(mode); for (let i = 0; i < 18; i++) { const a = i * 20 + t.frameCount; const cx = Math.cos(a) * (5 + (i % 3) * 4); const cy = Math.sin(a) * (5 + (i % 4) * 2); const size = 2 + Math.sin(time + i) * 0.8; t.char(i % 2 ? '^' : '#'); t.charColor(250, 110 + i * 6, 150 + i * 3); t.cellColor(40 + i * 4, 10, 25); t.vertex(cx + Math.cos(a) * size, cy + Math.sin(a) * size); t.vertex(cx + Math.cos(a + 120) * size, cy + Math.sin(a + 120) * size); t.vertex(cx + Math.cos(a + 240) * size, cy + Math.sin(a + 240) * size); } t.endShape(); }); labelLayer.draw(() => { t.clear(); const left = -Math.floor(t.grid.cols / 2); const top = -Math.floor(t.grid.rows / 2); let y = top + 3; const x = left + 3; drawText('TEXTMODIFIER.TRIANGLES', x, y++, 100, 255, 140); drawText('------------------------------------', x, y++, 80, 100, 150); drawText('CONCEPT: INDEPENDENT FACETS', x, y++, 100, 220, 255); drawText('Every three vertices fill.', x, y++, 140, 160, 190); drawText('Each triangle stands alone.', x, y++, 140, 160, 190); drawText('------------------------------------', x, y++, 80, 100, 150); drawText(MODE: ${modeName}, x, y++, 140, 255, 180); }); t.windowResized(() => { t.resizeCanvas(window.innerWidth, window.innerHeight); });