Experimenting with stroke, fill, and classic Superman trail effects
movieCreditsSim7.html
Stage 7 explores two major visual enhancements inspired by the original Superman (1978) credits:
Request: "In version 7, let's experiment with a stroke and fill setting on the text. Using variables let's see how things look with a stroke and thickness and no fill, or with combinations we can try with variables. Let's also try an effect where the text leaves a 'trail' in the background, as seen in the Superman credits."
Goals:
Key Techniques to Implement:
Added comprehensive text appearance controls:
// ============================================
// STAGE 7: TEXT APPEARANCE CONFIGURATION
// ============================================
// *** TEXT STROKE (OUTLINE) SETTINGS ***
// Enable or disable stroke (outline) on text
const TEXT_STROKE_ENABLED = true;
// Stroke width in pixels
// Larger values = thicker outline
const TEXT_STROKE_WIDTH = 2;
// Stroke color (HSB mode)
const TEXT_STROKE_HUE = 0; // 0 with sat=0 = white/gray/black
const TEXT_STROKE_SATURATION = 0; // 0 = grayscale
const TEXT_STROKE_BRIGHTNESS = 100; // 100 = white outline
// *** TEXT FILL SETTINGS ***
// Enable or disable fill (interior) on text
const TEXT_FILL_ENABLED = true;
Default Configuration:
Why separate enable flags?
Why HSB color controls?
Created centralized function to apply stroke/fill styling:
/**
* STAGE 7: NEW FUNCTION - Applies stroke and fill styling to text
*
* This function centralizes all stroke/fill logic in one place,
* making it easy to experiment with different text appearances.
*/
function applyTextStyle(hue, opacity) {
// Apply stroke (outline) if enabled
if (TEXT_STROKE_ENABLED) {
stroke(TEXT_STROKE_HUE, TEXT_STROKE_SATURATION,
TEXT_STROKE_BRIGHTNESS, opacity);
strokeWeight(TEXT_STROKE_WIDTH);
} else {
noStroke();
}
// Apply fill (interior color) if enabled
if (TEXT_FILL_ENABLED) {
fill(hue, 80, 100, opacity);
} else {
noFill();
}
}
Why create a separate function?
Parameters:
Where called:
Opacity propagation: Function receives opacity from caller, applies to both stroke and fill. This ensures fade effects work correctly - as text fades, both outline and interior fade together!
Added controls for the classic Superman trail effect:
// ============================================
// STAGE 7: MOTION TRAIL CONFIGURATION
// ============================================
// *** MOTION TRAIL SETTINGS ***
// Creates the classic Superman effect where text leaves a fading trail
// Enable or disable motion trails
const TRAIL_ENABLED = true;
// Trail fade speed (0-255)
// Lower values = longer trails (slow fade)
// Higher values = shorter trails (fast fade)
const TRAIL_FADE_AMOUNT = 10;
// Trail fade method
const TRAIL_FADE_METHOD = "overlay";
TRAIL_FADE_AMOUNT impact:
Recommended starting values:
Created drawBackgroundWithTrails() to implement frame persistence:
/**
* STAGE 7: Draws the space background with optional motion trails
*
* Motion trails work by NOT completely clearing the previous frame.
* Instead, we draw a semi-transparent black rectangle over the canvas,
* which gradually fades the old content while keeping it slightly visible.
*/
function drawBackgroundWithTrails() {
if (TRAIL_ENABLED && TRAIL_FADE_METHOD === "overlay") {
// *** TRAIL EFFECT: Semi-transparent fade ***
push();
noStroke();
// Map TRAIL_FADE_AMOUNT (0-255) to alpha in HSB mode (0-100)
let fadeAlpha = map(TRAIL_FADE_AMOUNT, 0, 255, 0, 100);
fill(0, 0, 0, fadeAlpha);
rect(0, 0, width, height);
pop();
// Draw stars on top of the fading layer
drawStars();
} else {
// No trails - completely clear background each frame
background(0, 0, 0);
drawStars();
}
}
Traditional Animation (No Trails):
background(0, 0, 0)Trail Effect (Frame Persistence):
fill(0, 0, 0, fadeAlpha)Mathematical Explanation:
Why stars need special handling:
Stars are redrawn fresh each frame because they're stationary - we want them at full brightness, not fading. Text moves, so we want trails; stars don't move, so we redraw them!
TEXT_STROKE_ENABLED = true
TEXT_STROKE_WIDTH = 2
TEXT_STROKE_HUE = 180 // Cyan
TEXT_STROKE_SATURATION = 100 // Full color
TEXT_STROKE_BRIGHTNESS = 100
TEXT_FILL_ENABLED = false // KEY: No fill!
TRAIL_ENABLED = true
TRAIL_FADE_AMOUNT = 5 // Long trails
Effect: Hollow cyan letters with long glowing trails - like neon signs in space!
TEXT_STROKE_ENABLED = true
TEXT_STROKE_WIDTH = 3 // Thick outline
TEXT_STROKE_HUE = 0
TEXT_STROKE_SATURATION = 0
TEXT_STROKE_BRIGHTNESS = 0 // Black outline
TEXT_FILL_ENABLED = true // Colored fill
TRAIL_ENABLED = false // No trails
Effect: Bold colored letters with thick black outlines - classic comic book text!
TEXT_STROKE_ENABLED = false
TEXT_FILL_ENABLED = true
TRAIL_ENABLED = true
TRAIL_FADE_AMOUNT = 3 // KEY: Very long trails!
Effect: Solid letters with extremely long fading trails - ethereal ghost effect!
TEXT_STROKE_ENABLED = true
TEXT_STROKE_WIDTH = 1
TEXT_STROKE_BRIGHTNESS = 100 // White outline
TEXT_FILL_ENABLED = true
TRAIL_ENABLED = true
TRAIL_FADE_AMOUNT = 50 // KEY: Very fast fade!
Effect: Outlined letters with barely visible trails - crisp, modern look with subtle motion!
TEXT_STROKE_ENABLED = false // Original had no outlines
TEXT_FILL_ENABLED = true
TRAIL_ENABLED = true
TRAIL_FADE_AMOUNT = 10 // Medium trails
Effect: Closest to original 1978 Superman credits - solid colored text with medium-length trails!
Every shape in p5.js has two components:
Control functions:
stroke(color) - Set outline colorstrokeWeight(width) - Set outline thicknessnoStroke() - Disable outlinefill(color) - Set interior colornoFill() - Make interior transparentDrawing order matters:
// CORRECT: Set style, then draw
stroke(0, 0, 100); // White outline
strokeWeight(2);
fill(180, 80, 100); // Cyan fill
text("Hello", 100, 100);
// WRONG: Draw first, style after (won't work!)
text("Hello", 100, 100);
stroke(0, 0, 100); // Too late!
State persistence:
Style settings persist until changed:
stroke(0, 0, 100);
text("A", 50, 50); // Has white stroke
text("B", 100, 50); // STILL has white stroke!
noStroke();
text("C", 150, 50); // Now no stroke
Why applyTextStyle() is called before each text():
Ensures correct styling is active for that specific text draw, regardless of what was set previously!
1. Stroke and Fill:
2. Frame Persistence:
3. Configuration-Driven Design:
4. Code Organization:
Revolutionary Technique:
Technical Approach (Original Film):
Our Digital Recreation:
Why This Matters:
"You will believe a man can fly" - and you can code like a Hollywood effects artist!
Task: Find the best stroke width for readability
Science: This is human factors research - how design affects perception!
Task: Calculate how long trails persist
Experiment: Verify by changing TRAIL_FADE_AMOUNT and timing with stopwatch!
Task: Create visually pleasing stroke + fill combinations
Try these color theory principles:
Question: Which combinations work best with motion trails?
Task: Measure how settings affect frame rate
// Add to draw() function to display frame rate
console.log("FPS:", frameRate());
Test configurations:
Questions: Which settings slow down the animation most? Why?
Task: Create your own unique style
Requirements:
Bonus: Create variables for multiple preset "themes" that can be switched!
Visual Flexibility:
Technical Achievement:
Educational Value:
New Variables Added:
Files Created:
๐ Stage 7 demonstrates how configuration-driven design enables endless experimentation - change a few variables and create completely different visual styles!
Possible Future Enhancements:
Advanced Experiments:
The visual possibilities are endless - keep experimenting! ๐๏ธ๐ปโจ