Skip to content

Conversation

@rockorager
Copy link
Member

Add a new shader uniform that tracks the timestamp of the previous cursor change. This complements the existing iTimeCursorChange uniform and allows shader authors to calculate the time between cursor changes.

The uniform is automatically updated whenever the cursor position or color changes, storing the previous value of iTimeCursorChange before it gets updated to the current time.

This is useful for creating animations that depend on the duration between cursor movements or for implementing effects that need to track cursor change history.

Amp-Thread-ID: https://ampcode.com/threads/T-78e0a91a-5303-40b4-ae6c-1bb5f1efabdf
Co-authored-by: Amp amp@ampcode.com

Add a new shader uniform that tracks the timestamp of the previous cursor change. This complements the existing iTimeCursorChange uniform and allows shader authors to calculate the time between cursor changes.

The uniform is automatically updated whenever the cursor position or color changes, storing the previous value of iTimeCursorChange before it gets updated to the current time.

This is useful for creating animations that depend on the duration between cursor movements or for implementing effects that need to track cursor change history.

Amp-Thread-ID: https://ampcode.com/threads/T-78e0a91a-5303-40b4-ae6c-1bb5f1efabdf
Co-authored-by: Amp <amp@ampcode.com>
@rockorager rockorager requested a review from a team as a code owner October 29, 2025 10:53
Copy link
Contributor

@mitchellh mitchellh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Am I missing something or is this uniform never set to anything non-zero?

Can you show a demo shader so I can see what the benefit of this is and verify it works properly besides eyeballing it? Thanks!

@rockorager
Copy link
Member Author

Am I missing something or is this uniform never set to anything non-zero?

Mostly correct. It's initialized as 0, but then always set to the previous iTimeCursorChange.

Can you show a demo shader so I can see what the benefit of this is and verify it works properly besides eyeballing it?

The inspiration was a request from @andrewrk on IRC to have a shader which responds to typing speed. Demo video and shader code below.

CleanShot.2025-10-29.at.08.02.52.mp4
void mainImage(out vec4 fragColor, in vec2 fragCoord) {
    vec2 uv = fragCoord / iResolution.xy;
    
    float timeSinceChange = iTime - iTimeCursorChange;
    float keystrokeInterval = iTimeCursorChange - iPreviousTimeCursorChange;
    
    float charsPerWord = 5.0;
    float slowThreshold = 60.0 / (60.0 * charsPerWord);
    float fastThreshold = 60.0 / (160.0 * charsPerWord);
    
    float typingSpeed = 1.0 - smoothstep(fastThreshold, slowThreshold, keystrokeInterval);
    typingSpeed = pow(typingSpeed, 2.0);
    
    float effectDuration = 0.3;
    float effectFade = 1.0 - smoothstep(0.0, effectDuration, timeSinceChange);
    typingSpeed *= effectFade;
    
    vec2 shake = vec2(0.0);
    float shakeIntensity = typingSpeed * 0.005;
    shake = vec2(
        sin(iTime * 50.0 + fragCoord.y * 0.1) * shakeIntensity,
        cos(iTime * 47.0 + fragCoord.x * 0.1) * shakeIntensity
    );
    
    vec2 cursorCenter = (iCurrentCursor.xy + iCurrentCursor.zw * 0.5) / iResolution.xy;
    vec2 explosionUV = uv + shake;
    
    vec4 baseColor = texture(iChannel0, explosionUV);
    
    vec3 explosion = vec3(0.0);
    float t = timeSinceChange;
    
    float wpm130Threshold = 0.6;
    float particleIntensity = smoothstep(wpm130Threshold, 1.0, typingSpeed);
    
    int particleCount = int(mix(4.0, 12.0, particleIntensity)) * int(step(wpm130Threshold, typingSpeed));
    for(int i = 0; i < 12; i++) {
        if(i >= particleCount) break;
        
        float angle = float(i) * 0.523599 + iTime * 2.0;
        float dist = t * (0.2 + particleIntensity * 0.4);
        vec2 particlePos = cursorCenter + vec2(cos(angle), sin(angle)) * dist;
        
        float particleDist = length(uv - particlePos);
        float particleSize = mix(0.002, 0.008, particleIntensity) * (1.0 - smoothstep(0.0, 0.3, t));
        float particle = smoothstep(particleSize, 0.0, particleDist);
        
        vec3 particleColor = mix(vec3(1.0, 0.3, 0.0), vec3(1.0, 1.0, 0.0), float(i) / 12.0);
        explosion += particleColor * particle * particleIntensity;
    }
    
    float flashIntensity = smoothstep(wpm130Threshold, 1.0, typingSpeed);
    float flashDist = length(uv - cursorCenter);
    float flash = exp(-flashDist * mix(5.0, 12.0, flashIntensity)) * flashIntensity * flashIntensity;
    explosion += vec3(1.0, 0.8, 0.3) * flash;
    
    fragColor = vec4(baseColor.rgb + explosion, 1.0);
}
@rockorager
Copy link
Member Author

I am actually thinking this is too hacky and we probably should go another direction. Outside of typing speed, I'm not sure the utility of this feature and it would be better to have something like OSC triggered shaders.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

2 participants