diff --git a/README.md b/README.md index 5191432..fdd4b7c 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,59 @@ # this-must-be-the-place--mural--colorblock-fx + + A canvas-based sign-painted block letter effect — white face, red mid-layer, black depth — inspired by the ["This Must Be The Place"](https://www.thebanner.com/community/local-news/this-must-be-the-place-mural-painted-espo-DMKP5D3IJNCWZEDL6NW6JOGKCE/) mural. + +![preview](preview.png) + + +## Quick start + +No build step. Open either file directly in a browser. + + +## How the effect works + +Three canvas draw passes, back to front: + +``` +1. Deep layer — drawn at offset (i, i) for i = depth…1 → black +2. Mid layer — drawn at offset (i, i) for i = depth×0.55…1 → red +3. Face layer — drawn at (0, 0) → white +``` + +This simulates physically mounted block letters casting a red then black shadow, the same technique used in hand-painted signs and murals. + +## Embedding in your own page + +Copy `embed.html` or paste the snippet below. The only dependency is the [Bebas Neue](https://fonts.google.com/specimen/Bebas+Neue) Google Font (falls back to Impact). + +```html + + +
+ +
+ + + + +``` + +## Options + +```js +blockLetterFX(canvas, text, { + faceColor: '#f0f0f0', // letter face + midColor: '#cc2200', // red mid-layer + deepColor: '#111111', // black depth + depthPct: 0.09, // extrusion as fraction of font size (0–0.25) + spacing: 2, // letter-spacing in px + padding: 28, // horizontal padding in px +}) +``` + +## License + +MIT diff --git a/block-letter-fx.js b/block-letter-fx.js new file mode 100644 index 0000000..fef9c06 --- /dev/null +++ b/block-letter-fx.js @@ -0,0 +1,78 @@ +(function (root, factory) { + if (typeof module !== 'undefined' && module.exports) module.exports = factory(); + else root.blockLetterFX = factory(); +})(typeof self !== 'undefined' ? self : this, function () { + + var DEFAULT_OPTS = { + faceColor: '#f0f0f0', + midColor: '#cc2200', + deepColor: '#111111', + depthPct: 0.09, + spacing: 2, + padding: 28, + }; + + function draw(canvas, text, opts) { + opts = Object.assign({}, DEFAULT_OPTS, opts || {}); + text = (text || '').trim() || 'BLOCK LETTER FX'; + + var ctx = canvas.getContext('2d'); + var DPR = window.devicePixelRatio || 1; + var LETTER_SPACING = opts.spacing; + var maxW = canvas.parentElement + ? canvas.parentElement.clientWidth - opts.padding * 2 + : 600; + + var fontSize = Math.round(maxW * 0.11); + ctx.font = 'normal ' + fontSize + 'px "Bebas Neue", Impact, sans-serif'; + var textW = ctx.measureText(text).width + LETTER_SPACING * text.length; + while (textW > maxW && fontSize > 8) { + fontSize--; + ctx.font = 'normal ' + fontSize + 'px "Bebas Neue", Impact, sans-serif'; + textW = ctx.measureText(text).width + LETTER_SPACING * text.length; + } + + var depth = Math.round(fontSize * opts.depthPct); + var padY = Math.round(fontSize * 0.2); + var cssW = textW + opts.padding * 2; + var cssH = fontSize + padY * 2 + depth; + + canvas.width = Math.round(cssW * DPR); + canvas.height = Math.round(cssH * DPR); + canvas.style.width = cssW + 'px'; + canvas.style.height = cssH + 'px'; + + ctx.scale(DPR, DPR); + ctx.clearRect(0, 0, cssW, cssH); + ctx.font = 'normal ' + fontSize + 'px "Bebas Neue", Impact, sans-serif'; + ctx.textBaseline = 'top'; + ctx.letterSpacing = LETTER_SPACING + 'px'; + + var x = opts.padding; + var y = padY; + + for (var i = depth; i >= 1; i--) { + ctx.fillStyle = opts.deepColor; + ctx.fillText(text, x + i, y + i); + } + for (var i = Math.round(depth * 0.55); i >= 1; i--) { + ctx.fillStyle = opts.midColor; + ctx.fillText(text, x + i, y + i); + } + ctx.fillStyle = opts.faceColor; + ctx.fillText(text, x, y); + } + + function blockLetterFX(canvas, text, opts) { + function render() { draw(canvas, text, opts); } + if (document.fonts && document.fonts.load) { + document.fonts.load('1em "Bebas Neue"').then(render); + } else { + setTimeout(render, 400); + } + window.addEventListener('resize', render); + return { redraw: render }; + } + + return blockLetterFX; +}); diff --git a/preview.png b/preview.png new file mode 100644 index 0000000..e580219 Binary files /dev/null and b/preview.png differ