076
LVL 03 — MID DEVELOPERSESSION 076DAY 76

TEXT TOOL

🎫 PIXELCRAFT-063
Feature | 🟠 Hard | Priority: 🟠 High

Users need to add text overlays to images — memes, annotations, watermarks. Click canvas → type text → choose font/size/color → position and rotate. Text as a moveable layer.
CONCEPTS.UNLOCKED
🔤
Canvas Text Rendering
fillText() and strokeText(). Set ctx.font = '48px Impact', pick a color, call fillText(). Canvas renders text as pixels — once drawn, it's just image data.
📏
measureText()
Know the size before you draw. ctx.measureText('Hello').width tells you how wide the text will be. Essential for centering, wrapping, and bounding box calculations.
🔠
Google Fonts Loading
Dynamic font loading with FontFace API. Load any Google Font at runtime: new FontFace('Lobster', 'url(...)') → document.fonts.add(). Wait for load before rendering.
📍
Text Positioning & Rotation
translate() + rotate() + fillText(). Move the canvas origin to the text position, rotate, draw text at (0,0), then restore. This is how rotated text works in every editor.
🎯
Bounding Box Hit Detection
Is the click inside the text? Calculate the text's bounding rectangle using measureText(). Check if mouse coordinates fall within it. This enables click-to-select and dragging.
✏️
contenteditable Overlays
HTML over Canvas for live editing. Position a contenteditable div over the canvas for typing. Once confirmed, render the text to canvas. Best of both worlds: HTML editing, Canvas rendering.
HANDS-ON.TASKS
01
Render Text on Canvas
function renderText(ctx, textObj) { ctx.save(); // Move origin to text position ctx.translate(textObj.x, textObj.y); ctx.rotate( textObj.rotation * Math.PI / 180); // Configure font ctx.font = `${textObj.bold ? 'bold ' : ''}` + `${textObj.size}px ${textObj.font}`; ctx.fillStyle = textObj.color; ctx.textAlign = textObj.align; ctx.textBaseline = 'top'; ctx.globalAlpha = textObj.opacity; // Draw text ctx.fillText(textObj.text, 0, 0); // Optional: stroke outline if (textObj.stroke) { ctx.strokeStyle = textObj.strokeColor; ctx.lineWidth = textObj.strokeWidth; ctx.strokeText(textObj.text, 0, 0); } ctx.restore(); }
02
Dynamic Google Fonts Loading
async function loadGoogleFont( fontFamily ) { const url = `https://fonts.googleapis.com/` + `css2?family=` + `${fontFamily.replace(/ /g, '+')}`; // Inject stylesheet const link = document.createElement('link'); link.href = url; link.rel = 'stylesheet'; document.head.appendChild(link); // Wait for font to actually load await document.fonts.load( `16px "${fontFamily}"` ); return fontFamily; } // Usage await loadGoogleFont('Lobster'); ctx.font = '48px Lobster'; ctx.fillText('Hello!', 100, 100);
Fonts must be fully loaded before Canvas can use them. If you draw text before the font loads, Canvas falls back to the default — a common bug in text tools.
03
Contenteditable Overlay for Live Editing
function TextOverlay({ position, font, size, color, onConfirm }) { const ref = useRef(null); useEffect(() => { ref.current?.focus(); }, []); const handleBlur = () => { const text = ref.current.innerText.trim(); if (text) onConfirm(text); }; return ( <div ref={ref} contentEditable suppressContentEditableWarning onBlur={handleBlur} onKeyDown={(e) => { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); ref.current.blur(); } }} style={{ position: 'absolute', left: position.x, top: position.y, font: `${size}px ${font}`, color: color, outline: 'none', minWidth: '100px', border: '1px dashed #fff4', }} /> ); }
04
Bounding Box & Drag-to-Move
function getTextBounds(ctx, textObj) { ctx.font = `${textObj.size}px ${textObj.font}`; const metrics = ctx.measureText(textObj.text); return { x: textObj.x, y: textObj.y, width: metrics.width, height: textObj.size * 1.2 }; } function isClickOnText( mouseX, mouseY, bounds ) { return ( mouseX >= bounds.x && mouseX <= bounds.x + bounds.width && mouseY >= bounds.y && mouseY <= bounds.y + bounds.height ); }
05
Close the Ticket
git switch -c feature/PIXELCRAFT-063-text-tool git add src/ git commit -m "Add text tool with fonts, rotation, drag (PIXELCRAFT-063)" git push origin feature/PIXELCRAFT-063-text-tool # PR → Review → Merge → Close ticket ✅
CS.DEEP-DIVE

Fonts are one of the most complex data structures in computing.

A single font file contains thousands of Bézier curves, kerning tables, ligatures, and hinting instructions.

// Inside a font file:

Glyphs
  Each letter = cubic Bézier curves
  The letter 'S' alone needs ~20
  control points

Kerning
  Adjusts spacing between pairs
  "AV" needs tighter spacing than "HH"

Hinting
  Instructions for rendering at
  small sizes on low-DPI screens

OpenType features
  Ligatures: "fi" → single glyph
  Stylistic alternates, swashes

// TrueType (Apple 1991), OpenType
// (Microsoft+Adobe 1996), WOFF2 (web)
// — all built on Bézier mathematics.
"Text Lab"
[A]Add multi-line text: support line breaks in the text overlay. Calculate line height, render each line separately with fillText(). Handle text wrapping at a max width.
[B]Add text effects: drop shadow (ctx.shadowColor/shadowBlur), gradient fill (createLinearGradient as fillStyle), and curved text along a path (measure and place each character).
[C]Build a meme generator: select from popular meme templates, add top/bottom text in Impact font with white fill and black stroke. Export as PNG with one click.
REF.MATERIAL
ARTICLE
MDN Web Docs
fillText, strokeText, measureText, font property, text alignment, and baseline. The complete Canvas text rendering guide.
CANVASTEXTESSENTIAL
ARTICLE
MDN Web Docs
Load fonts dynamically in JavaScript. Create FontFace objects, add to document.fonts, and detect when fonts are ready to render.
FONTSMDNOFFICIAL
VIDEO
Fireship
Quick tour of typography: serifs, kerning, ligatures, and why font choice matters. The visual context behind the code.
TYPOGRAPHYQUICK
ARTICLE
Google
1,600+ free fonts. Browse, preview, and get embed URLs. The largest free font library on the web.
FONTSRESOURCE
VIDEO
Linus Boman
Inside font design: from hand-drawn sketches to Bézier curves to kerning tables. How a font goes from idea to file.
FONTSDESIGN
// LEAVE EXCITED BECAUSE
Click the canvas → type text → choose any Google Font → drag it into position → rotate it. Text is a first-class layer now. You just built the core of every meme generator and social media editor on the internet.