{"id":51682034,"url":"https://github.com/smyrgeorge/pyeffects","last_synced_at":"2026-07-15T14:33:43.175Z","repository":{"id":368041089,"uuid":"1283240964","full_name":"smyrgeorge/pyeffects","owner":"smyrgeorge","description":"A small desktop app (and CLI) for applying creative effects to your photos — with a built-in video renderer that animates an effect over time.","archived":false,"fork":false,"pushed_at":"2026-06-28T19:08:33.000Z","size":2792,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-28T21:07:09.674Z","etag":null,"topics":["animation","chromatic-aberration","creative-coding","ffmpeg","glitch","glitch-art","glitch-effect","image-effects","image-processing","numpy","photo-editor","python","video-rendering"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/smyrgeorge.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":"smyrgeorge"}},"created_at":"2026-06-28T17:47:21.000Z","updated_at":"2026-06-28T19:08:36.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/smyrgeorge/pyeffects","commit_stats":null,"previous_names":["smyrgeorge/pyeffects"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/smyrgeorge/pyeffects","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/smyrgeorge%2Fpyeffects","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/smyrgeorge%2Fpyeffects/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/smyrgeorge%2Fpyeffects/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/smyrgeorge%2Fpyeffects/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/smyrgeorge","download_url":"https://codeload.github.com/smyrgeorge/pyeffects/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/smyrgeorge%2Fpyeffects/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35509495,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-15T02:00:06.706Z","response_time":131,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["animation","chromatic-aberration","creative-coding","ffmpeg","glitch","glitch-art","glitch-effect","image-effects","image-processing","numpy","photo-editor","python","video-rendering"],"created_at":"2026-07-15T14:33:41.894Z","updated_at":"2026-07-15T14:33:43.154Z","avatar_url":"https://github.com/smyrgeorge.png","language":"Python","funding_links":["https://github.com/sponsors/smyrgeorge"],"categories":[],"sub_categories":[],"readme":"# PyEffects\n\nA curated collection of creative photo effects — preview them live, run them from the CLI, or animate them into video.\n\n## About\n\n![PyEffects desktop app](docs/img/screenshot.png)\n\nPyEffects is a lightweight Python toolkit for applying image effects. It ships with a reusable GUI that shows a\nbefore/after slider and builds its settings controls **dynamically** from whichever effect is selected. Adding a new\neffect only means implementing a small interface and registering it — the UI and command-line parser adapt\nautomatically, and `python src/utils/gen_previews.py` renders its before/after preview for this README.\n\nIt also **renders videos**: pick an effect, choose a *from → to* range for any of its variables (or several at once),\nand PyEffects interpolates those values across the frames and encodes a smooth MP4 — animating, for example, the\n*Height* effect ramping from 0 to 100% strength. Frames render in parallel across your CPU cores and ffmpeg smooths\nthe motion.\n\nFive effects ship in the box:\n\n- **Glitch** — RGB shift, slice displacement, noise, and scanlines.\n- **Glitch Height** — a radial 3D-extrusion effect: the image bursts outward from a focal point into strong,\n  pointed, feathery spikes that grow toward the edges, with an optional circular frame.\n- **Night** — a neon \"night\" stylisation: the background is crushed to black while the in-focus subject glows in a\n  cool teal/amber palette, with posterised banding, a vignette, and optional chunky shard shredding.\n- **Pixelate** — a blocky mosaic / pixel-art look, with optional retro color banding and soft blocks.\n- **Pop Art** — a Warhol-style silkscreen: a 2×2 grid where each quadrant is recoloured through a different duotone\n  palette, finished with a halftone dot screen and paper texture.\n\n\u003e [!NOTE]\n\u003e More effects are on the way — this is an ongoing project, and the collection keeps growing.\n\n### Examples\n\nEach effect shown in the app's before/after view.\n\n**Glitch** — RGB shift, slice displacement, and scanlines:\n\n![Glitch effect before/after](docs/img/glitch.png)\n\n**Glitch Height** — radial 3D extrusion bursting from a focal point:\n\n![Glitch Height effect before/after](docs/img/glitch-height.png)\n\n**Night** — a neon \"night\" stylisation with a cool teal/amber palette:\n\n![Night effect before/after](docs/img/night.png)\n\n**Pixelate** — a blocky mosaic / pixel-art look:\n\n![Pixelate effect before/after](docs/img/pixelate.png)\n\n**Pop Art** — a Warhol-style four-up silkscreen with a halftone dot screen:\n\n![Pop Art effect before/after](docs/img/pop-art.png)\n\n### Video\n\nAny effect can be animated over time. You choose a *from → to* range for one or more of its parameters; PyEffects then\nrenders a frame at each step along that range (in parallel across your CPU cores), and **ffmpeg** interpolates the\nin-between frames and encodes them into a smooth MP4. Below, the *Glitch Height* effect ramps its **strength** from 0 to\n100%:\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"docs/img/glitch-height.gif\" alt=\"Glitch Height video — strength ramped 0 → 100%\" width=\"400\"\u003e\n\u003c/p\u003e\n\n\u003e See [**Video (animated parameters)**](#video-animated-parameters) below for the full list of rendering options.\n\n## Setup\n\n### Initialize Python Environment\n\nCreate and activate a virtual environment:\n\n```bash\npython3 -m venv .venv\nsource .venv/bin/activate  # On Windows: .venv\\Scripts\\activate\n```\n\n### Install Requirements\n\n```bash\npip install -r requirements.txt\n```\n\n\u003e [!NOTE]\n\u003e The GUI uses [PySide6](https://doc.qt.io/qtforpython/) (Qt). On macOS the bundled Homebrew Python may not include\n\u003e Tkinter, which is why PySide6 is used instead — it installs as a self-contained wheel.\n\n## Usage\n\n### Desktop app (GUI)\n\n```bash\npython src/ui/app.py\n```\n\n1. Click **Open…** and choose an image.\n2. Drag the **vertical divider** over the image to wipe between the original (left, *BEFORE*) and the processed result\n   (right, *AFTER*).\n3. Adjust the effect settings on the right — the preview updates live.\n4. Below the effect settings, click **Save image…** to export the result at full resolution.\n5. In the **Render video** panel below it, set the duration, frame rate, frame count, resolution (native input size by\n   default — capped to 4K so the clip plays back smoothly — or untick to set a smaller cap), and smoothing, and use the\n   **Transitions** rows to set a *from → to* range for any effect variable (by default the strength ramps 0 → 100%).\n   Each panel has a **Reset**. Click **Render video…** to export the animation: a progress bar tracks the frames, then a\n   live **ffmpeg log** shows the encode, with a **Cancel** button. Frames render in parallel across your CPU cores.\n\nThe preview is computed on a downscaled copy for responsiveness; exporting always re-renders at full resolution.\n\n### Command line\n\nEach effect is also runnable headless. Its options are generated from the same settings the GUI uses:\n\n```bash\npython src/effects/glitch.py path/to/image.jpg\npython src/effects/glitch.py workspace/photo.jpg --rgb-shift 0.6 --slices 30 --noise 0.1 --seed 7\n```\n\nBy default the result is written next to the original as `\u003cname\u003e_glitch.\u003cext\u003e` (use `-o` to override). Run with\n`--help` to see every option.\n\n#### Glitch settings\n\n| Setting     | CLI flag        | Description                                               | Default |\n|-------------|-----------------|-----------------------------------------------------------|---------|\n| RGB shift   | `--rgb-shift`   | Chromatic aberration: how far the red/blue channels slide | `0.5`   |\n| Slices      | `--slices`      | Number of displaced horizontal bands                      | `20`    |\n| Slice shift | `--slice-shift` | Max horizontal displacement per band (fraction of width)  | `0.10`  |\n| Noise       | `--noise`       | Amount of random color speckle                            | `0.0`   |\n| Scanlines   | `--scanlines`   | Strength of the darkened CRT-style scanlines              | `0.15`  |\n| Seed        | `--seed`        | Random seed (same seed → same glitch)                     | `42`    |\n\n#### Glitch Height settings\n\n```bash\npython src/effects/glitch_height.py path/to/image.jpg\npython src/effects/glitch_height.py workspace/photo.jpg --strength 0.6 --center-y 0.55\n```\n\n| Setting        | CLI flag      | Description                                       | Default |\n|----------------|---------------|---------------------------------------------------|---------|\n| Strength       | `--strength`  | Length of the radial extrusion spikes             | `0.25`  |\n| Center X       | `--center-x`  | Horizontal focal point (0 = left, 1 = right)      | `0.5`   |\n| Center Y       | `--center-y`  | Vertical focal point (0 = top, 1 = bottom)        | `0.5`   |\n| Detail         | `--detail`    | Number of extrusion steps (higher = smoother)     | `100`   |\n| Circular frame | `--circle`    | Mask the result to a circle, fading corners black | off     |\n| Scanlines      | `--scanlines` | Strength of the darkened CRT-style scanlines      | `0.0`   |\n\n#### Night settings\n\n```bash\npython src/effects/night.py path/to/image.jpg\npython src/effects/night.py workspace/photo.jpg --streaks 0.85 --levels 6 --vignette 0.8\n```\n\nThe background is crushed to black while the in-focus subject glows in a cool teal/amber palette — the colour follows\nthe subject's own hue, so warm features (eyes, nose, ears) turn amber while neutral fur and whiskers read cool. It is\nfinished with posterised banding, a vignette, and a fine grain. Turn up `--streaks` for a chunky, shredded \"shard\" look.\n\n| Setting      | CLI flag     | Description                                                     | Default |\n|--------------|--------------|-----------------------------------------------------------------|---------|\n| Strength     | `--strength` | Blend between the original and the full night stylisation       | `1.0`   |\n| Detail glow  | `--detail`   | How strongly textured/in-focus areas light up vs. fade to black | `0.5`   |\n| Streaks      | `--streaks`  | Boldness of the hard-edged streak/block shredding (0 = smooth)  | `0.0`   |\n| Color levels | `--levels`   | Posterise each channel to this many levels (banding)            | `8`     |\n| Grain        | `--grain`    | Amount of fine film grain                                       | `0.035` |\n| Vignette     | `--vignette` | Darkening of the corners toward black                           | `0.7`   |\n\n#### Pixelate settings\n\n```bash\npython src/effects/pixelate.py path/to/image.jpg\npython src/effects/pixelate.py workspace/photo.jpg --pixel-size 0.06 --levels 8 --smooth\n```\n\n| Setting       | CLI flag       | Description                                                      | Default |\n|---------------|----------------|------------------------------------------------------------------|---------|\n| Pixel size    | `--pixel-size` | Block size as a fraction of the longest edge (bigger = chunkier) | `0.03`  |\n| Color levels  | `--levels`     | Quantise each channel to N levels (256 = full color)             | `256`   |\n| Smooth blocks | `--smooth`     | Bilinear upscaling for soft blocks instead of hard pixels        | off     |\n\n#### Pop Art settings\n\n```bash\npython src/effects/popart.py path/to/image.jpg\npython src/effects/popart.py workspace/photo.jpg --contrast 0.7 --dots 0.6 --dot-size 0.012\n```\n\nThe image is laid out as a 2×2 grid and each quadrant is recoloured through a different two/three-tone gradient map\n(maroon/olive, magenta/periwinkle, blue/yellow, green/pink), then overlaid with a halftone dot screen and a subtle\npaper texture — the classic Warhol silkscreen.\n\n| Setting       | CLI flag     | Description                                             | Default |\n|---------------|--------------|---------------------------------------------------------|---------|\n| Strength      | `--strength` | Blend between the original and the full pop-art result  | `1.0`   |\n| Contrast      | `--contrast` | Tonal punch before the colour mapping (higher = bolder) | `0.5`   |\n| Halftone      | `--dots`     | Strength of the halftone dot screen                     | `0.5`   |\n| Dot size      | `--dot-size` | Halftone cell size as a fraction of the quadrant width  | `0.01`  |\n| Paper texture | `--texture`  | Amount of canvas/paper grain over the print             | `0.3`   |\n\n### Video (animated parameters)\n\nRender an MP4 that animates an effect over time. Give any of its parameters a *from → to* range and PyEffects\ninterpolates them across the frames while holding every other parameter constant — animate a single variable or\nseveral at once. By default it ramps the **strength** from 0 to 100%:\n\n```bash\npython src/render/video.py workspace/photo.jpg                 # height effect, 10s @ 30fps\npython src/render/video.py workspace/photo.jpg -e height -d 15 --frames 200 --smooth motion\npython src/render/video.py workspace/photo.jpg --transition strength:0:1 --transition center_y:0.4:0.6\n```\n\n| Option     | CLI flag        | Description                                        | Default        |\n|------------|-----------------|----------------------------------------------------|----------------|\n| Effect     | `-e/--effect`   | Effect id to animate (`glitch`, `height`, …)       | `height`       |\n| Output     | `-o/--output`   | Output `.mp4` path                                 | `\u003cname\u003e.mp4`   |\n| Parameter  | `-p/--param`    | Parameter to animate (when `--transition` not set) | `strength`     |\n| Transition | `--transition`  | `NAME:FROM:TO`, repeatable — animate several vars  | strength 0→max |\n| Duration   | `-d/--duration` | Video length in seconds                            | `10`           |\n| Frame rate | `--fps`         | Output frames per second                           | `30`           |\n| Frames     | `--frames`      | Distinct frames rendered across the animation      | `100`          |\n| Max size   | `--max-size`    | Longest edge of the video in px (capped at 3840)   | `1024`         |\n| Smoothing  | `--smooth`      | In-between frames: `blend`, `motion`, or `none`    | `blend`        |\n| Workers    | `--workers`     | Frames rendered in parallel                        | CPU count      |\n\nThe frames are rendered into a folder named `_\u003cimage-stem\u003e` next to the image, then encoded to `\u003cimage-stem\u003e.mp4`.\nBecause each frame of an effect like *Height* is expensive, only `--frames` distinct frames are rendered (one per\nstep) — in parallel across `--workers` threads. **ffmpeg** then fills the gap up to `--fps` either by interpolating\nsmooth in-between frames (`--smooth blend`/`motion`) or by duplicating frames (`--smooth none`), so the video runs the\nfull `--duration` and stays smooth. Raise `--frames` for crisper motion (slower), lower it for a quicker render.\nEncoding uses a bundled ffmpeg (`imageio-ffmpeg`) or a system `ffmpeg` if present.\n\n## License\n\n[MIT](LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsmyrgeorge%2Fpyeffects","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsmyrgeorge%2Fpyeffects","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsmyrgeorge%2Fpyeffects/lists"}