Sync all skills and memories 2026-04-14 07:27
This commit is contained in:
302
skills/creative/p5js/references/typography.md
Normal file
302
skills/creative/p5js/references/typography.md
Normal file
@@ -0,0 +1,302 @@
|
||||
# Typography
|
||||
|
||||
## Loading Fonts
|
||||
|
||||
### System Fonts
|
||||
|
||||
```javascript
|
||||
textFont('Helvetica');
|
||||
textFont('Georgia');
|
||||
textFont('monospace');
|
||||
```
|
||||
|
||||
### Custom Fonts (OTF/TTF/WOFF2)
|
||||
|
||||
```javascript
|
||||
let myFont;
|
||||
|
||||
function preload() {
|
||||
myFont = loadFont('path/to/font.otf');
|
||||
// Requires local server or CORS-enabled URL
|
||||
}
|
||||
|
||||
function setup() {
|
||||
textFont(myFont);
|
||||
}
|
||||
```
|
||||
|
||||
### Google Fonts via CSS
|
||||
|
||||
```html
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap" rel="stylesheet">
|
||||
<script>
|
||||
function setup() {
|
||||
textFont('Inter');
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
Google Fonts work without `loadFont()` but only for `text()` — not for `textToPoints()`. For particle text, you need `loadFont()` with an OTF/TTF file.
|
||||
|
||||
## Text Rendering
|
||||
|
||||
### Basic Text
|
||||
|
||||
```javascript
|
||||
textSize(32);
|
||||
textAlign(CENTER, CENTER);
|
||||
text('Hello World', width/2, height/2);
|
||||
```
|
||||
|
||||
### Text Properties
|
||||
|
||||
```javascript
|
||||
textSize(48); // pixel size
|
||||
textAlign(LEFT, TOP); // horizontal: LEFT, CENTER, RIGHT
|
||||
// vertical: TOP, CENTER, BOTTOM, BASELINE
|
||||
textLeading(40); // line spacing (for multi-line text)
|
||||
textStyle(BOLD); // NORMAL, BOLD, ITALIC, BOLDITALIC
|
||||
textWrap(WORD); // WORD or CHAR (for text() with max width)
|
||||
```
|
||||
|
||||
### Text Metrics
|
||||
|
||||
```javascript
|
||||
let w = textWidth('Hello'); // pixel width of string
|
||||
let a = textAscent(); // height above baseline
|
||||
let d = textDescent(); // height below baseline
|
||||
let totalH = a + d; // full line height
|
||||
```
|
||||
|
||||
### Text Bounding Box
|
||||
|
||||
```javascript
|
||||
let bounds = myFont.textBounds('Hello', x, y, size);
|
||||
// bounds = { x, y, w, h }
|
||||
// Useful for positioning, collision, background rectangles
|
||||
```
|
||||
|
||||
### Multi-Line Text
|
||||
|
||||
```javascript
|
||||
// With max width — auto wraps
|
||||
textWrap(WORD);
|
||||
text('Long text that wraps within the given width', x, y, maxWidth);
|
||||
|
||||
// With max width AND height — clips
|
||||
text('Very long text', x, y, maxWidth, maxHeight);
|
||||
```
|
||||
|
||||
## textToPoints() — Text as Particles
|
||||
|
||||
Convert text outline to array of points. Requires a loaded font (OTF/TTF via `loadFont()`).
|
||||
|
||||
```javascript
|
||||
let font;
|
||||
let points;
|
||||
|
||||
function preload() {
|
||||
font = loadFont('font.otf'); // MUST be loadFont, not CSS
|
||||
}
|
||||
|
||||
function setup() {
|
||||
createCanvas(1200, 600);
|
||||
points = font.textToPoints('HELLO', 100, 400, 200, {
|
||||
sampleFactor: 0.1, // lower = more points (0.1-0.5 typical)
|
||||
simplifyThreshold: 0
|
||||
});
|
||||
}
|
||||
|
||||
function draw() {
|
||||
background(0);
|
||||
for (let pt of points) {
|
||||
let n = noise(pt.x * 0.01, pt.y * 0.01, frameCount * 0.01);
|
||||
fill(255, n * 255);
|
||||
noStroke();
|
||||
ellipse(pt.x + random(-2, 2), pt.y + random(-2, 2), 3);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Particle Text Class
|
||||
|
||||
```javascript
|
||||
class TextParticle {
|
||||
constructor(target) {
|
||||
this.target = createVector(target.x, target.y);
|
||||
this.pos = createVector(random(width), random(height));
|
||||
this.vel = createVector(0, 0);
|
||||
this.acc = createVector(0, 0);
|
||||
this.maxSpeed = 10;
|
||||
this.maxForce = 0.5;
|
||||
}
|
||||
|
||||
arrive() {
|
||||
let desired = p5.Vector.sub(this.target, this.pos);
|
||||
let d = desired.mag();
|
||||
let speed = d < 100 ? map(d, 0, 100, 0, this.maxSpeed) : this.maxSpeed;
|
||||
desired.setMag(speed);
|
||||
let steer = p5.Vector.sub(desired, this.vel);
|
||||
steer.limit(this.maxForce);
|
||||
this.acc.add(steer);
|
||||
}
|
||||
|
||||
flee(target, radius) {
|
||||
let d = this.pos.dist(target);
|
||||
if (d < radius) {
|
||||
let desired = p5.Vector.sub(this.pos, target);
|
||||
desired.setMag(this.maxSpeed);
|
||||
let steer = p5.Vector.sub(desired, this.vel);
|
||||
steer.limit(this.maxForce * 2);
|
||||
this.acc.add(steer);
|
||||
}
|
||||
}
|
||||
|
||||
update() {
|
||||
this.vel.add(this.acc);
|
||||
this.vel.limit(this.maxSpeed);
|
||||
this.pos.add(this.vel);
|
||||
this.acc.mult(0);
|
||||
}
|
||||
|
||||
display() {
|
||||
fill(255);
|
||||
noStroke();
|
||||
ellipse(this.pos.x, this.pos.y, 3);
|
||||
}
|
||||
}
|
||||
|
||||
// Usage: particles form text, scatter from mouse
|
||||
let textParticles = [];
|
||||
for (let pt of points) {
|
||||
textParticles.push(new TextParticle(pt));
|
||||
}
|
||||
|
||||
function draw() {
|
||||
background(0);
|
||||
for (let p of textParticles) {
|
||||
p.arrive();
|
||||
p.flee(createVector(mouseX, mouseY), 80);
|
||||
p.update();
|
||||
p.display();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Kinetic Typography
|
||||
|
||||
### Wave Text
|
||||
|
||||
```javascript
|
||||
function waveText(str, x, y, size, amplitude, frequency) {
|
||||
textSize(size);
|
||||
textAlign(LEFT, BASELINE);
|
||||
let xOff = 0;
|
||||
for (let i = 0; i < str.length; i++) {
|
||||
let yOff = sin(frameCount * 0.05 + i * frequency) * amplitude;
|
||||
text(str[i], x + xOff, y + yOff);
|
||||
xOff += textWidth(str[i]);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Typewriter Effect
|
||||
|
||||
```javascript
|
||||
class Typewriter {
|
||||
constructor(str, x, y, speed = 50) {
|
||||
this.str = str;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.speed = speed; // ms per character
|
||||
this.startTime = millis();
|
||||
this.cursor = true;
|
||||
}
|
||||
|
||||
display() {
|
||||
let elapsed = millis() - this.startTime;
|
||||
let chars = min(floor(elapsed / this.speed), this.str.length);
|
||||
let visible = this.str.substring(0, chars);
|
||||
|
||||
textAlign(LEFT, TOP);
|
||||
text(visible, this.x, this.y);
|
||||
|
||||
// Blinking cursor
|
||||
if (chars < this.str.length && floor(millis() / 500) % 2 === 0) {
|
||||
let cursorX = this.x + textWidth(visible);
|
||||
line(cursorX, this.y, cursorX, this.y + textAscent() + textDescent());
|
||||
}
|
||||
}
|
||||
|
||||
isDone() { return millis() - this.startTime >= this.str.length * this.speed; }
|
||||
}
|
||||
```
|
||||
|
||||
### Character-by-Character Animation
|
||||
|
||||
```javascript
|
||||
function animatedText(str, x, y, size, delay = 50) {
|
||||
textSize(size);
|
||||
textAlign(LEFT, BASELINE);
|
||||
let xOff = 0;
|
||||
|
||||
for (let i = 0; i < str.length; i++) {
|
||||
let charStart = i * delay;
|
||||
let t = constrain((millis() - charStart) / 500, 0, 1);
|
||||
let et = easeOutElastic(t);
|
||||
|
||||
push();
|
||||
translate(x + xOff, y);
|
||||
scale(et);
|
||||
let alpha = t * 255;
|
||||
fill(255, alpha);
|
||||
text(str[i], 0, 0);
|
||||
pop();
|
||||
|
||||
xOff += textWidth(str[i]);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Text as Mask
|
||||
|
||||
```javascript
|
||||
let textBuffer;
|
||||
|
||||
function setup() {
|
||||
createCanvas(800, 800);
|
||||
textBuffer = createGraphics(width, height);
|
||||
textBuffer.background(0);
|
||||
textBuffer.fill(255);
|
||||
textBuffer.textSize(200);
|
||||
textBuffer.textAlign(CENTER, CENTER);
|
||||
textBuffer.text('MASK', width/2, height/2);
|
||||
}
|
||||
|
||||
function draw() {
|
||||
// Draw content
|
||||
background(0);
|
||||
// ... render something colorful
|
||||
|
||||
// Apply text mask (show content only where text is white)
|
||||
loadPixels();
|
||||
textBuffer.loadPixels();
|
||||
for (let i = 0; i < pixels.length; i += 4) {
|
||||
let maskVal = textBuffer.pixels[i]; // white = show, black = hide
|
||||
pixels[i + 3] = maskVal; // set alpha from mask
|
||||
}
|
||||
updatePixels();
|
||||
}
|
||||
```
|
||||
|
||||
## Responsive Text Sizing
|
||||
|
||||
```javascript
|
||||
function responsiveTextSize(baseSize, baseWidth = 1920) {
|
||||
return baseSize * (width / baseWidth);
|
||||
}
|
||||
|
||||
// Usage
|
||||
textSize(responsiveTextSize(48));
|
||||
text('Scales with canvas', width/2, height/2);
|
||||
```
|
||||
Reference in New Issue
Block a user