docs: add screenshots section to README with composed collage
Three-panel collage (popup, before, after) generated via Pillow script. 4:3 aspect ratio, 1200px max, gradient background with drop shadows. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
13
README.md
13
README.md
@@ -14,6 +14,19 @@ A Firefox extension that reskins [old.reddit.com](https://old.reddit.com) with a
|
|||||||
- **Color customization** — per-subreddit badge colors via an inline HSV picker
|
- **Color customization** — per-subreddit badge colors via an inline HSV picker
|
||||||
- **Theming** — separate light/dark palettes with automatic RES night-mode detection
|
- **Theming** — separate light/dark palettes with automatic RES night-mode detection
|
||||||
|
|
||||||
|
## Screenshots
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
> Extension menu (left), standard old.reddit.com (top right), with extension enabled (bottom right).
|
||||||
|
> RES (Reddit Enhancement Suite) was enabled during capture.
|
||||||
|
|
||||||
|
| View | Full-size image |
|
||||||
|
|---|---|
|
||||||
|
| Extension menu | [reddit-extension-popup.png](docs/reddit-extension-popup.png) |
|
||||||
|
| Without extension | [reddit-extension-disabled.png](docs/reddit-extension-disabled.png) |
|
||||||
|
| With extension | [reddit-extension-enabled.png](docs/reddit-extension-enabled.png) |
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
1. Clone or download this repo
|
1. Clone or download this repo
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
# README Screenshots
|
||||||
|
|
||||||
|
## Task
|
||||||
|
|
||||||
|
Add a Screenshots section to the README featuring a composed collage hero image and links to each full-size original screenshot.
|
||||||
|
|
||||||
|
## Changes Made
|
||||||
|
|
||||||
|
### New files
|
||||||
|
- `docs/make_collage.py` -- Python/Pillow script that composes the three source screenshots into an 800x600 collage image (popup left, disabled top-right, enabled bottom-right, light gray background, 4px gaps).
|
||||||
|
- `docs/reddit-extension-collage.png` -- the generated collage output.
|
||||||
|
|
||||||
|
### Modified files
|
||||||
|
- `README.md` -- added a "Screenshots" section between "What it does" and "Installation" containing the collage image, a blockquote caption describing the layout and noting RES was active during capture, and a table linking to each full-size original.
|
||||||
|
|
||||||
|
## Source screenshots
|
||||||
|
- `docs/reddit-extension-popup.png` (645x2757) -- captured by user by opening `moz-extension://<uuid>/popup/popup.html` in a Firefox tab
|
||||||
|
- `docs/reddit-extension-disabled.png` (2794x1671) -- old.reddit.com without extension
|
||||||
|
- `docs/reddit-extension-enabled.png` (2794x1671) -- old.reddit.com with extension
|
||||||
|
|
||||||
|
## Lessons Learned
|
||||||
|
- Firefox extension popups close on focus loss. Opening the popup HTML directly via `moz-extension://` URL in a regular tab is the simplest workaround for full-page captures.
|
||||||
|
- GitHub-flavored markdown cannot crop images, does not honor `rowspan`, and strips most CSS. A pre-composed collage image is the only way to get a multi-panel layout.
|
||||||
|
- Pillow's `Image.LANCZOS` resampling produces clean downscaled screenshots even at significant reduction ratios (e.g., 2794px down to ~546px).
|
||||||
|
|
||||||
|
## Follow-up
|
||||||
|
- The `docs/make_collage.py` script can be re-run if source screenshots are updated.
|
||||||
|
- Consider adding the collage script or output to `.gitignore` if the generated image shouldn't be tracked separately from sources.
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
# README Screenshots -- Final
|
||||||
|
|
||||||
|
## Task
|
||||||
|
|
||||||
|
Add a Screenshots section to the README with a composed collage hero image and links to full-size originals.
|
||||||
|
|
||||||
|
## Changes Made
|
||||||
|
|
||||||
|
### New files
|
||||||
|
- `docs/reddit-extension-collage.png` -- 1200x900 (4:3) composed collage of all three screenshots.
|
||||||
|
- `docs/make_collage.py` -- Pillow script that generates the collage. Configurable aspect ratio, max dimension, gradient, borders, and drop shadows.
|
||||||
|
- `docs/reddit-extension-popup.png` -- full-page capture of the extension popup (captured manually via `moz-extension://` URL in a tab).
|
||||||
|
- `docs/reddit-extension-disabled.png` -- old.reddit.com without the extension.
|
||||||
|
- `docs/reddit-extension-enabled.png` -- old.reddit.com with the extension active.
|
||||||
|
|
||||||
|
### Modified files
|
||||||
|
- `README.md` -- added Screenshots section between "What it does" and "Installation". Contains the collage hero image, a blockquote caption, and a table linking to each full-size original.
|
||||||
|
|
||||||
|
## Collage Details
|
||||||
|
|
||||||
|
Final collage configuration after iterating through multiple options:
|
||||||
|
- **Layout**: popup on left, disabled screenshot top-right, enabled screenshot bottom-right
|
||||||
|
- **Aspect ratio**: 4:3, clamped to 1200px max dimension (chosen from 5:4, 4:3, 3:2, 16:10, 16:9, 6:5, 7:6 variants)
|
||||||
|
- **Background**: 45-degree linear gradient from `#888888` to `#575757`
|
||||||
|
- **Panel borders**: `#111111`, 1px, 4px corner radius
|
||||||
|
- **Drop shadows**: offset (4,4), blur 8, rgba(0,0,0,0.43), cast bottom-right to complement the gradient angle
|
||||||
|
- **Padding**: 20px outer, 14px gaps between panels (scaled proportionally when clamped)
|
||||||
|
|
||||||
|
## Lessons Learned
|
||||||
|
- Firefox extension popups close on focus loss. Opening `moz-extension://<uuid>/popup/popup.html` in a regular tab is the simplest workaround for full-page captures.
|
||||||
|
- GitHub-flavored markdown cannot crop images, strips `rowspan`, and removes CSS. A pre-composed collage image is the only way to get a multi-panel layout in a README.
|
||||||
|
- Iterating on visual output (colors, ratios, effects) works well as a rapid generate-and-review loop with Pillow.
|
||||||
|
- Generating multiple aspect ratio variants at once and letting the user compare side-by-side is faster than guessing one at a time.
|
||||||
|
|
||||||
|
## Follow-up
|
||||||
|
- Run `python docs/make_collage.py` to regenerate the collage if source screenshots are updated.
|
||||||
186
docs/make_collage.py
Normal file
186
docs/make_collage.py
Normal file
@@ -0,0 +1,186 @@
|
|||||||
|
"""Compose a collage from three extension screenshots.
|
||||||
|
|
||||||
|
Layout (with padding and gaps):
|
||||||
|
+--padding--+---gap---+-----padding-----+
|
||||||
|
| | | |
|
||||||
|
| popup | | disabled (right) |
|
||||||
|
| (left) | +---------gap------+
|
||||||
|
| | | enabled (right) |
|
||||||
|
| | | |
|
||||||
|
+--padding--+---------+-----padding-----+
|
||||||
|
|
||||||
|
Usage: python docs/make_collage.py
|
||||||
|
"""
|
||||||
|
|
||||||
|
import math
|
||||||
|
from pathlib import Path
|
||||||
|
from PIL import Image, ImageDraw, ImageFilter
|
||||||
|
|
||||||
|
DOCS = Path(__file__).parent
|
||||||
|
|
||||||
|
PAD = 20
|
||||||
|
GAP = 14
|
||||||
|
GRAD_START = (136, 136, 136)
|
||||||
|
GRAD_END = (87, 87, 87)
|
||||||
|
GRAD_ANGLE_DEG = 45
|
||||||
|
|
||||||
|
POPUP_COL_W = 230
|
||||||
|
|
||||||
|
BORDER_COLOR = (17, 17, 17)
|
||||||
|
BORDER_W = 1
|
||||||
|
CORNER_R = 4
|
||||||
|
|
||||||
|
SHADOW_OFFSET = (4, 4)
|
||||||
|
SHADOW_BLUR = 8
|
||||||
|
SHADOW_COLOR = (0, 0, 0, 110)
|
||||||
|
|
||||||
|
|
||||||
|
def scale_and_crop(img, target_w, target_h):
|
||||||
|
"""Scale image to cover target box, then crop from top-left."""
|
||||||
|
scale = max(target_w / img.width, target_h / img.height)
|
||||||
|
new_w = round(img.width * scale)
|
||||||
|
new_h = round(img.height * scale)
|
||||||
|
img = img.resize((new_w, new_h), Image.LANCZOS)
|
||||||
|
return img.crop((0, 0, target_w, target_h))
|
||||||
|
|
||||||
|
|
||||||
|
def make_gradient(w, h):
|
||||||
|
"""Create a linear gradient background at GRAD_ANGLE_DEG degrees."""
|
||||||
|
angle = math.radians(GRAD_ANGLE_DEG)
|
||||||
|
dx, dy = math.cos(angle), math.sin(angle)
|
||||||
|
pixels = []
|
||||||
|
for y in range(h):
|
||||||
|
for x in range(w):
|
||||||
|
t = (x * dx + y * dy) / (w * dx + h * dy)
|
||||||
|
t = max(0.0, min(1.0, t))
|
||||||
|
r = round(GRAD_START[0] + (GRAD_END[0] - GRAD_START[0]) * t)
|
||||||
|
g = round(GRAD_START[1] + (GRAD_END[1] - GRAD_START[1]) * t)
|
||||||
|
b = round(GRAD_START[2] + (GRAD_END[2] - GRAD_START[2]) * t)
|
||||||
|
pixels.append((r, g, b))
|
||||||
|
img = Image.new("RGB", (w, h))
|
||||||
|
img.putdata(pixels)
|
||||||
|
return img
|
||||||
|
|
||||||
|
|
||||||
|
def round_corners(img, radius):
|
||||||
|
"""Apply rounded corners using an alpha mask."""
|
||||||
|
img = img.convert("RGBA")
|
||||||
|
mask = Image.new("L", img.size, 255)
|
||||||
|
draw = ImageDraw.Draw(mask)
|
||||||
|
draw.rectangle([0, 0, radius, radius], fill=0)
|
||||||
|
draw.rectangle([img.width - radius, 0, img.width, radius], fill=0)
|
||||||
|
draw.rectangle([0, img.height - radius, radius, img.height], fill=0)
|
||||||
|
draw.rectangle([img.width - radius, img.height - radius, img.width, img.height], fill=0)
|
||||||
|
draw.pieslice([0, 0, radius * 2, radius * 2], 180, 270, fill=255)
|
||||||
|
draw.pieslice([img.width - radius * 2, 0, img.width, radius * 2], 270, 360, fill=255)
|
||||||
|
draw.pieslice([0, img.height - radius * 2, radius * 2, img.height], 90, 180, fill=255)
|
||||||
|
draw.pieslice([img.width - radius * 2, img.height - radius * 2, img.width, img.height], 0, 90, fill=255)
|
||||||
|
img.putalpha(mask)
|
||||||
|
return img
|
||||||
|
|
||||||
|
|
||||||
|
def add_border(img, color, width, radius):
|
||||||
|
"""Draw a rounded-rect border on an RGBA image."""
|
||||||
|
draw = ImageDraw.Draw(img)
|
||||||
|
draw.rounded_rectangle(
|
||||||
|
[0, 0, img.width - 1, img.height - 1],
|
||||||
|
radius=radius, outline=color, width=width,
|
||||||
|
)
|
||||||
|
return img
|
||||||
|
|
||||||
|
|
||||||
|
def make_shadow(w, h, radius):
|
||||||
|
"""Create a drop shadow image for a panel of size w x h."""
|
||||||
|
spread = SHADOW_BLUR * 2
|
||||||
|
sw = w + spread * 2
|
||||||
|
sh = h + spread * 2
|
||||||
|
shadow = Image.new("RGBA", (sw, sh), (0, 0, 0, 0))
|
||||||
|
draw = ImageDraw.Draw(shadow)
|
||||||
|
draw.rounded_rectangle(
|
||||||
|
[spread, spread, spread + w, spread + h],
|
||||||
|
radius=radius, fill=SHADOW_COLOR,
|
||||||
|
)
|
||||||
|
shadow = shadow.filter(ImageFilter.GaussianBlur(SHADOW_BLUR))
|
||||||
|
return shadow
|
||||||
|
|
||||||
|
|
||||||
|
def paste_panel(canvas, panel_img, x, y):
|
||||||
|
"""Paste a panel onto the canvas with rounded corners, border, and drop shadow."""
|
||||||
|
w, h = panel_img.size
|
||||||
|
panel = round_corners(panel_img, CORNER_R)
|
||||||
|
panel = add_border(panel, BORDER_COLOR, BORDER_W, CORNER_R)
|
||||||
|
|
||||||
|
shadow = make_shadow(w, h, CORNER_R)
|
||||||
|
spread = SHADOW_BLUR * 2
|
||||||
|
sx = x + SHADOW_OFFSET[0] - spread
|
||||||
|
sy = y + SHADOW_OFFSET[1] - spread
|
||||||
|
canvas.paste(shadow, (sx, sy), shadow)
|
||||||
|
|
||||||
|
canvas.paste(panel, (x, y), panel)
|
||||||
|
|
||||||
|
|
||||||
|
ASPECT_RATIO = (4, 3)
|
||||||
|
MAX_DIMENSION = 1200
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
popup = Image.open(DOCS / "reddit-extension-popup.png")
|
||||||
|
disabled = Image.open(DOCS / "reddit-extension-disabled.png")
|
||||||
|
enabled = Image.open(DOCS / "reddit-extension-enabled.png")
|
||||||
|
|
||||||
|
popup_scale = POPUP_COL_W / popup.width
|
||||||
|
popup_natural_h = round(popup.height * popup_scale)
|
||||||
|
|
||||||
|
right_col_w = 700
|
||||||
|
right_panel_h = (popup_natural_h - GAP) // 2
|
||||||
|
|
||||||
|
content_h = popup_natural_h
|
||||||
|
content_w = POPUP_COL_W + GAP + right_col_w
|
||||||
|
|
||||||
|
shadow_extra = max(SHADOW_OFFSET[0], SHADOW_OFFSET[1]) + SHADOW_BLUR
|
||||||
|
inner_w = content_w + 2 * PAD + shadow_extra
|
||||||
|
inner_h = content_h + 2 * PAD + shadow_extra
|
||||||
|
|
||||||
|
aspect_w, aspect_h = ASPECT_RATIO
|
||||||
|
target_w = max(inner_w, round(inner_h * aspect_w / aspect_h))
|
||||||
|
target_h = max(inner_h, round(target_w * aspect_h / aspect_w))
|
||||||
|
|
||||||
|
# Clamp to MAX_DIMENSION, scaling down proportionally
|
||||||
|
if max(target_w, target_h) > MAX_DIMENSION:
|
||||||
|
scale_down = MAX_DIMENSION / max(target_w, target_h)
|
||||||
|
target_w = round(target_w * scale_down)
|
||||||
|
target_h = round(target_h * scale_down)
|
||||||
|
inner_w = round(inner_w * scale_down)
|
||||||
|
inner_h = round(inner_h * scale_down)
|
||||||
|
popup_natural_h = round(popup_natural_h * scale_down)
|
||||||
|
right_col_w = round(right_col_w * scale_down)
|
||||||
|
right_panel_h = round(right_panel_h * scale_down)
|
||||||
|
popup_col_w = round(POPUP_COL_W * scale_down)
|
||||||
|
pad = round(PAD * scale_down)
|
||||||
|
gap = round(GAP * scale_down)
|
||||||
|
else:
|
||||||
|
popup_col_w = POPUP_COL_W
|
||||||
|
pad = PAD
|
||||||
|
gap = GAP
|
||||||
|
|
||||||
|
canvas = make_gradient(target_w, target_h).convert("RGBA")
|
||||||
|
|
||||||
|
x_off = (target_w - inner_w) // 2
|
||||||
|
y_off = (target_h - inner_h) // 2
|
||||||
|
|
||||||
|
popup_resized = popup.resize((popup_col_w, popup_natural_h), Image.LANCZOS)
|
||||||
|
paste_panel(canvas, popup_resized, x_off + pad, y_off + pad)
|
||||||
|
|
||||||
|
rx = x_off + pad + popup_col_w + gap
|
||||||
|
paste_panel(canvas, scale_and_crop(disabled, right_col_w, right_panel_h), rx, y_off + pad)
|
||||||
|
paste_panel(canvas, scale_and_crop(enabled, right_col_w, right_panel_h), rx, y_off + pad + right_panel_h + gap)
|
||||||
|
|
||||||
|
out = DOCS / "reddit-extension-collage.png"
|
||||||
|
canvas.convert("RGB").save(out, optimize=True)
|
||||||
|
print(f"Saved {out} ({target_w}x{target_h})")
|
||||||
|
print(f"Popup: {popup_col_w}x{popup_natural_h} (showing 100%)")
|
||||||
|
print(f"Right panels: {right_col_w}x{right_panel_h} each")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
BIN
docs/reddit-extension-collage.png
Normal file
BIN
docs/reddit-extension-collage.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 417 KiB |
BIN
docs/reddit-extension-disabled.png
Normal file
BIN
docs/reddit-extension-disabled.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 912 KiB |
BIN
docs/reddit-extension-enabled.png
Normal file
BIN
docs/reddit-extension-enabled.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 709 KiB |
BIN
docs/reddit-extension-popup.png
Normal file
BIN
docs/reddit-extension-popup.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 207 KiB |
Reference in New Issue
Block a user