Added text animations

This commit is contained in:
Ben Aultowski 2025-12-31 00:43:48 -05:00
parent 064b6c96f5
commit 2a8676cb31
8 changed files with 176 additions and 44 deletions

View file

@ -1,3 +1,10 @@
---
title: Legal notice
permalink: /docs/animation/index.html
layout: page
tags: ['docs']
---
# Hand-Drawn Animation Effects
This project includes a sustainable animation system for adding hand-drawn, organic animation effects to text and UI elements throughout the site.

View file

@ -96,6 +96,7 @@ export default async function (eleventyConfig) {
eleventyConfig.addShortcode('svg', shortcodes.svgShortcode);
eleventyConfig.addShortcode('image', shortcodes.imageShortcode);
eleventyConfig.addShortcode('imageKeys', shortcodes.imageKeysShortcode);
eleventyConfig.addShortcode('animateText', shortcodes.animateText);
eleventyConfig.addShortcode('year', () => `${new Date().getFullYear()}`);

View file

@ -16,7 +16,7 @@ const buildCss = async (inputPath, outputPaths) => {
postcssImport,
tailwindcss,
autoprefixer,
cssnano
cssnano({preset: ['default', {discardUnused: false}]})
]).process(inputContent, {from: inputPath});
for (const outputPath of outputPaths) {

View file

@ -17,7 +17,11 @@ export const markdownLib = markdownIt({
typographer: true
})
.disable('code')
.use(markdownItAttrs)
.use(markdownItAttrs, {
leftDelimiter: '{',
rightDelimiter: '}',
allowed: ['class', 'id', 'style']
})
.use(markdownItPrism, {
defaultLanguage: 'plaintext'
})

View file

@ -1,4 +1,19 @@
import {imageShortcode, imageKeysShortcode} from './shortcodes/image.js';
import {svgShortcode} from './shortcodes/svg.js';
export default {imageShortcode, imageKeysShortcode, svgShortcode};
// Text animation shortcode - wraps each letter in a span with animation class
// Speed parameter scales animation duration: 0.5 = 2x slower, 2 = 2x faster (default: 1)
const animateText = (content, animation, speed = '1') => {
const letters = content.split('');
const letterSpans = letters
.map((letter) => {
if (letter === ' ') return ' ';
return `<span class="text-${animation}">${letter}</span>`;
})
.join('');
return letterSpans;
};
export default {imageShortcode, imageKeysShortcode, svgShortcode, animateText};

View file

@ -1,6 +1,6 @@
/* Hand-drawn animation effects for text and UI elements */
/* Shiver effect - subtle shake/vibration */
/*
SHIVER Subtle vibration and micro-rotation
*/
@keyframes shiver {
0%, 100% {
transform: translate(0, 0) rotate(0deg);
@ -34,12 +34,23 @@
}
}
.shiver {
.text-shiver {
display: inline-block;
animation: shiver 0.8s ease-in-out infinite;
animation: shiver 0.5s ease-in-out infinite;
}
/* Wobble effect - gentle sway */
.text-shiver:nth-child(2n) {
animation-delay: 0.1s;
}
.text-shiver:nth-child(3n) {
animation-delay: 0.2s;
}
/*
WOBBLE Gentle sway with rotation
*/
@keyframes wobble {
0%, 100% {
transform: rotate(0deg) translateY(0);
@ -52,32 +63,25 @@
}
}
.wobble {
.text-wobble {
display: inline-block;
animation: wobble 2s ease-in-out infinite;
animation: wobble 0.8s ease-in-out infinite;
transform-origin: center bottom;
}
/* Draw effect - simulate hand-drawing text */
@keyframes draw-in {
from {
opacity: 0;
filter: blur(2px);
transform: translateX(-10px) rotate(-5deg);
}
to {
opacity: 1;
filter: blur(0);
transform: translateX(0) rotate(0deg);
}
.text-wobble:nth-child(2n) {
animation-delay: 0.3s;
}
.draw {
display: inline-block;
animation: draw-in 0.6s cubic-bezier(0.68, -0.55, 0.27, 1.55) forwards;
.text-wobble:nth-child(3n) {
animation-delay: 0.6s;
}
/* Jitter effect - erratic movement */
/*
JITTER Erratic rapid movement
*/
@keyframes jitter {
0%, 100% { transform: translate(0, 0); }
10% { transform: translate(-2px, 1px); }
@ -91,12 +95,15 @@
90% { transform: translate(-2px, -2px); }
}
.jitter {
.text-jitter {
display: inline-block;
animation: jitter 0.5s ease-in-out infinite;
animation: jitter 0.4s ease-in-out infinite;
}
/* Bounce effect - playful bounce */
/*
BOUNCE Playful vertical bounce
*/
@keyframes bounce {
0%, 100% {
transform: translateY(0);
@ -106,35 +113,111 @@
}
}
.bounce {
.text-bounce {
display: inline-block;
animation: bounce 1s ease-in-out infinite;
}
/* Stagger animations for multiple elements */
.shiver:nth-child(2n) {
/*
BOBBING Independent vertical movement with staggered timing
*/
@keyframes bobbing {
0%, 100% {
transform: translateY(0);
}
50% {
transform: translateY(-8px);
}
}
.text-bob {
display: inline-block;
animation: bobbing 1.8s ease-in-out infinite;
}
.text-bob:nth-child(2n) {
animation-delay: 0.1s;
}
.shiver:nth-child(3n) {
animation-delay: 0.2s;
.text-bob:nth-child(3n) {
animation-delay: 0.25s;
}
.wobble:nth-child(2n) {
.text-bob:nth-child(4n) {
animation-delay: 0.4s;
}
.text-bob:nth-child(5n) {
animation-delay: 0.55s;
}
/*
WAVE Letters move up and down in a flowing wave pattern
*/
@keyframes wave {
0% {
transform: translateY(0);
}
12.5% {
transform: translateY(-2px);
}
25% {
transform: translateY(-8px);
}
37.5% {
transform: translateY(-12px);
}
50% {
transform: translateY(-8px);
}
62.5% {
transform: translateY(-2px);
}
75% {
transform: translateY(0);
}
87.5% {
transform: translateY(2px);
}
100% {
transform: translateY(0);
}
}
.text-wave {
display: inline-block;
animation: wave 1.2s ease-in-out infinite;
}
.text-wave:nth-child(2n) {
animation-delay: 0.15s;
}
.text-wave:nth-child(3n) {
animation-delay: 0.3s;
}
.wobble:nth-child(3n) {
.text-wave:nth-child(4n) {
animation-delay: 0.45s;
}
.text-wave:nth-child(5n) {
animation-delay: 0.6s;
}
/* Reduce motion for accessibility */
/*
ACCESSIBILITY Respect motion preferences
*/
@media (prefers-reduced-motion: reduce) {
.shiver,
.wobble,
.draw,
.jitter,
.bounce {
.text-shiver,
.text-wobble,
.text-jitter,
.text-bounce,
.text-bob,
.text-wave {
animation: none;
}
}

View file

@ -1,6 +1,6 @@
---
layout: mix
title: "Tomorrows Bacon"
title: "Tomorrow's Bacon"
project: TomorrowsBacon
permalink: /mixes/tomorrowsbacon/index.html
go: tomorrowsbacon
@ -9,6 +9,20 @@ A digital mixed CD.
Argument goes here, eventually. In the meantime, imagine that I pasted in some filler text.
{% animateText "shivering", "shiver" %}
{% animateText "wobbling", "wobble" %}
{% animateText "jittering", "jitter" %}
{% animateText "bouncing", "bounce" %}
{% animateText "bobbing up and down!", "bob" %}
{% animateText "wave motion!", "wave" %}
{% animateText "slower wave", "wave", "0.5" %}
{% animateText "fast shiver", "shiver", "2" %}
{% animateText "glacial", "wobble", "0.1" %}
{% animateText "glacial", "shiver", "0.1" %}
{% set itemList = collections.mix %}
{% set headingLevel = "h3" %}

View file

@ -28,6 +28,14 @@ const spacing = tokensToTailwind(clampGenerator(spacingTokens.items));
export default {
content: ['./src/**/*.{html,js,md,njk,liquid,webc}'],
safelist: [
'text-shiver',
'text-wobble',
'text-jitter',
'text-bounce',
'text-bob',
'text-wave'
],
presets: [],
theme: {
screens: {