-
-
Notifications
You must be signed in to change notification settings - Fork 445
Description
Please confirm the following points:
- This feature request is NOT for the Android apps in the Play Store
- I have searched the project page to check if a similar request was already made
Application or Project
I don't know / Multiple / Other (please elaborate below)
Is Your Enhancement Related to a Problem?
Flashing lights may cause epileptic seizures. To try to prevent seizures, add a visual output filter ((also) with zero guarantee o promoting the feature).
Your Suggested Enhancement
What hertz or other patterns would need to be filtered to prevent causing epileptic seizures with a music visualization?
How would you add this safety feature to projectm?
According to Gemini 3 (an AI LLM model) FWIW:
Title: Feature Request: Photosensitivity Safety Filter (Epilepsy Protection)
Is your feature request related to a problem? Please describe.
Music visualizations, by nature, often contain rapid strobing, high-contrast flashing, and geometric patterns that can trigger Photosensitive Epilepsy (PSE).
Currently, projectM renders presets exactly as written by the community. Since many presets rely on rapid tan(time) oscillations or frame-inverting strobes, the software creates a high risk for users with seizure disorders. There is currently no "gatekeeper" in the rendering pipeline to ensure output remains within safe physiological limits (e.g., WCAG or Harding FPA standards).
Describe the solution you'd like
I propose implementing a Global Post-Processing Safety Shader.
Instead of editing thousands of .milk files, we should add a final render pass that intercepts the image before it hits the screen. This pass acts as a "Limiter" or "Compressor," but for luminance and flash frequency rather than audio volume.
Safety Criteria to Enforce:
- Frequency Cap: Strictly limit full-screen luminance changes to < 3 Hz (3 flashes per second).
- Chromatic Damping: Detect and dampen high-saturation Red (660–720 nm) transitions, which are statistically more dangerous.
- Slew Rate Limiting: Force rapid black-to-white transitions to fade over several frames rather than toggling instantly.
Technical Implementation
We can achieve this by adding a safety_pass.frag shader in the post-processing pipeline. This requires retaining the Previous Frame texture to compare against the Current Frame.
1. The Shader Logic (GLSL Prototype)
This shader calculates the difference in luminance between the current frame and the last frame. If the difference exceeds a safe delta (calculated based on FPS to ensure <3Hz modulation), it clamps the pixel's brightness.
// safety_pass.frag
#version 330 core
uniform sampler2D u_CurrentFrame; // Output from projectM
uniform sampler2D u_HistoryFrame; // Output shown to user last frame
uniform float u_SafeDelta; // Max allowed brightness change per frame
in vec2 v_TexCoord;
out vec4 FragColor;
float getLuma(vec3 color) {
return dot(color, vec3(0.299, 0.587, 0.114));
}
void main() {
vec4 current = texture(u_CurrentFrame, v_TexCoord);
vec4 previous = texture(u_HistoryFrame, v_TexCoord);
// 1. Red Dampener (Desaturate dangerous red flashes)
if (current.r > 0.8 && current.g < 0.2 && current.b < 0.2) {
current.rgb = mix(current.rgb, vec3(current.r * 0.5), 0.5);
}
// 2. Temporal Luminance Limiter
float lumaCur = getLuma(current.rgb);
float lumaPrev = getLuma(previous.rgb);
float diff = lumaCur - lumaPrev;
// If change is too fast (Strobe detected)
if (abs(diff) > u_SafeDelta) {
// Clamp to maximum safe step
float targetLuma = lumaPrev + sign(diff) * u_SafeDelta;
// Apply scaling to RGB to maintain color, just darker/lighter
float scale = targetLuma / (lumaCur + 0.0001);
current.rgb *= scale;
}
FragColor = current;
}- C++ Integration Strategy
In ProjectM::renderFrame (or equivalent render loop):
-
- Render Preset: Render the visualization to an internal FBO as normal.
-
- Calculate Delta: Determine u_SafeDelta dynamically based on current FPS.
Formula: 1.0 / (CurrentFPS / 3.0)
- Calculate Delta: Determine u_SafeDelta dynamically based on current FPS.
-
- Apply Safety Pass: Bind the Safety Shader. Pass the current FBO and the History FBO as textures.
-
- Swap: Render result to screen and copy result to History FBO for the next frame.
Alternative Consideration: Preset Pruning
If a shader implementation is too resource-intensive for specific embedded targets, a secondary solution would be a Python script included in the tools directory that parses .milk files to detect and delete presets containing high-frequency triggers (e.g., searching for high-frequency sin/tan waves on monitor or ob_r variables).
Adding this feature might allow projectM to be used with less risk by users with photosensitive epilepsy, significantly increasing the accessibility of the project (and hopefully preventing injury and increasing enjoyment)
Alternative Solutions
Preset pruning
Additional Context
I do not and cannot warrant any of this for fitness for purpose; I offer this (initial ai 'slop') in hopes of reducing probability of photoepileptic seizure.