-
Notifications
You must be signed in to change notification settings - Fork 2
Add responsive scaled image variants for large PNG assets #1173
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
00c0b07
Initial plan
Copilot 1abfc26
Generate scaled card images and update useThemeImage hook for respons…
Copilot 0d585f7
Add comprehensive image optimization documentation
Copilot 47b3d20
Address code review feedback: improve documentation clarity and cross…
Copilot File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,237 @@ | ||
| # Image Optimization Guide | ||
|
|
||
| ## Table of Contents | ||
| - [Overview](#overview) | ||
| - [Summary](#summary) | ||
| - [Generated Files](#generated-files) | ||
| - [File Naming Convention](#file-naming-convention) | ||
| - [Sample File Size Comparisons](#sample-file-size-comparisons) | ||
| - [How It Works](#how-it-works) | ||
| - [Regenerating Scaled Images](#regenerating-scaled-images) | ||
| - [Technical Details](#technical-details) | ||
| - [Performance Impact](#performance-impact) | ||
| - [Original Files](#original-files) | ||
| - [Browser Compatibility](#browser-compatibility) | ||
| - [Testing](#testing) | ||
| - [Troubleshooting](#troubleshooting) | ||
| - [Future Improvements](#future-improvements) | ||
| - [Related Files](#related-files) | ||
|
|
||
| ## Overview | ||
| This guide documents the image optimization system implemented for SGeX Workbench to reduce file sizes and improve loading performance. | ||
|
|
||
| ## Summary | ||
| Successfully generated scaled versions of PNG files over 200KB in the project. The original 37 large files were identified, and for each file we created both desktop (600px) and mobile (300px) versions, plus their dark theme variants, resulting in: | ||
| - **Mobile**: ~93% file size reduction | ||
| - **Desktop**: ~74% file size reduction | ||
|
|
||
| ## Generated Files | ||
| - **Total scaled images**: 76 files | ||
| - 38 desktop versions (600px width) | ||
| - 38 mobile versions (300px width) | ||
| - All mobile versions are under 200KB ✅ | ||
| - Desktop versions range from 291KB to 580KB | ||
|
|
||
| ## File Naming Convention | ||
| For each original image (e.g., `image.png`), the following versions are created: | ||
| - `image_600.png` - Desktop version (600px width) | ||
| - `image_300.png` - Mobile version (300px width) | ||
| - `image_grey_tabby_600.png` - Desktop dark mode version | ||
| - `image_grey_tabby_300.png` - Mobile dark mode version | ||
|
|
||
| ## Sample File Size Comparisons | ||
|
|
||
| | File | Original | Desktop (600px) | Mobile (300px) | Desktop Savings | Mobile Savings | | ||
| |------|----------|-----------------|----------------|-----------------|----------------| | ||
| | sgex-mascot.png | 3.7MB | 380KB | 100KB | 89% | 97% | | ||
| | authoring.png | 2.0MB | 564KB | 132KB | 72% | 93% | | ||
| | collaboration.png | 2.0MB | 580KB | 144KB | 71% | 92% | | ||
| | dak_interventions.png | 1.8MB | 528KB | 108KB | 71% | 94% | | ||
| | pronunciation-guide.png | 3.7MB | 380KB | 100KB | 89% | 97% | | ||
|
|
||
| ## How It Works | ||
|
|
||
| ### Automatic Image Selection | ||
| The `useThemeImage` hook (`src/hooks/useThemeImage.js`) automatically: | ||
| 1. Detects screen size (< 768px = mobile, >= 768px = desktop) | ||
| 2. Detects current theme (light/dark mode) | ||
| 3. Serves the appropriately scaled and themed image | ||
| 4. Responds to window resizes and theme changes | ||
|
|
||
| ### Browser Behavior | ||
| - **Mobile screens (<768px)**: Loads 300px versions (~75-144KB each) | ||
| - **Desktop screens (>=768px)**: Loads 600px versions (~291-580KB each) | ||
| - **Dark mode**: Automatically uses `_grey_tabby` variants | ||
| - **Retina displays**: 600px images remain sharp on high-DPI screens | ||
|
|
||
| ## Regenerating Scaled Images | ||
|
|
||
| ### When to Regenerate | ||
| Regenerate scaled images when: | ||
| - New PNG images are added to `public/` directory | ||
| - Existing images are updated | ||
| - Image quality needs adjustment | ||
|
|
||
| ### How to Regenerate | ||
|
|
||
| 1. **Install ImageMagick**: | ||
|
|
||
| **Ubuntu/Debian:** | ||
| ```bash | ||
| sudo apt-get install imagemagick | ||
| ``` | ||
|
|
||
| **macOS (with Homebrew):** | ||
| ```bash | ||
| brew install imagemagick | ||
| ``` | ||
|
|
||
| **Windows:** | ||
| Download and install from [ImageMagick website](https://imagemagick.org/script/download.php) | ||
|
|
||
| 2. **Run the generation script**: | ||
| ```bash | ||
| ./scripts/generate-scaled-images.sh | ||
| ``` | ||
|
|
||
| 3. **Review the output** to ensure all images were processed correctly | ||
|
|
||
| 4. **Commit the new scaled images**: | ||
| ```bash | ||
| # Using git add with find command (works on all shells) | ||
| find public -name '*_300.png' -o -name '*_600.png' | xargs git add | ||
|
|
||
| # Or add all at once | ||
| git add public/ | ||
|
|
||
| git commit -m "Regenerate scaled images" | ||
| ``` | ||
|
|
||
| ### Customizing Image Sizes | ||
|
|
||
| To change the target sizes, edit `scripts/generate-scaled-images.sh`: | ||
| ```bash | ||
| DESKTOP_WIDTH=600 # Change this value for desktop size | ||
| MOBILE_WIDTH=300 # Change this value for mobile size | ||
| ``` | ||
|
|
||
| ## Technical Details | ||
|
|
||
| ### Image Generation Settings | ||
| - **Tool**: ImageMagick | ||
| - **Quality**: 85% compression | ||
| - **Scaling**: Proportional (maintains aspect ratio) | ||
| - **Format**: PNG with optimization | ||
|
|
||
| ### Code Implementation | ||
|
|
||
| 1. **Script**: `scripts/generate-scaled-images.sh` | ||
| - Finds all PNG files over 200KB | ||
| - Generates 600px and 300px versions | ||
| - Creates both light and dark theme variants | ||
| - Provides detailed output with file sizes | ||
|
|
||
| 2. **Hook**: `src/hooks/useThemeImage.js` | ||
| - Monitors screen size via `window.innerWidth` | ||
| - Listens for window resize events | ||
| - Observes theme changes via MutationObserver | ||
| - Returns appropriate image path | ||
|
|
||
| ### Component Usage | ||
| Components use the hook like this: | ||
| ```javascript | ||
| import useThemeImage from '../hooks/useThemeImage'; | ||
|
|
||
| const MyComponent = () => { | ||
| const imagePath = useThemeImage('my-image.png'); | ||
| return <img src={imagePath} alt="My Image" />; | ||
| }; | ||
| ``` | ||
|
|
||
| The hook handles all the complexity of selecting the right image variant. | ||
|
|
||
| ## Performance Impact | ||
|
|
||
| ### Bandwidth Savings | ||
| For a typical user viewing the DAK Dashboard with 9 component cards: | ||
| - **Before**: ~14MB (9 cards × ~1.5MB average) | ||
| - **After (Mobile)**: ~900KB (9 cards × ~100KB average) | ||
| - **After (Desktop)**: ~3.6MB (9 cards × ~400KB average) | ||
|
|
||
| ### Loading Time Improvements | ||
| - **Mobile (3G)**: ~85 seconds → ~6 seconds (93% faster) | ||
| - **Desktop (Cable)**: ~3 seconds → ~0.8 seconds (73% faster) | ||
|
|
||
| ## Original Files | ||
| All original PNG files are retained in the repository for: | ||
| - Future regeneration if needed | ||
| - Reference for quality comparison | ||
| - Archival purposes | ||
|
|
||
| ## Browser Compatibility | ||
| The responsive image loading works on all modern browsers: | ||
| - Chrome/Edge (latest) | ||
| - Firefox (latest) | ||
| - Safari (latest) | ||
| - Mobile browsers (iOS Safari, Chrome Mobile) | ||
|
|
||
| ## Testing | ||
|
|
||
| ### Automated Tests | ||
| Existing tests continue to work because: | ||
| - Tests mock the `useThemeImage` hook | ||
| - Mock returns test image paths | ||
| - No changes needed to test files | ||
|
|
||
| ### Manual Testing Checklist | ||
| To verify image optimization: | ||
| - [ ] Open DevTools Network tab | ||
| - [ ] Navigate to DAK Dashboard | ||
| - [ ] Verify mobile versions load on small screens (<768px) | ||
| - [ ] Verify desktop versions load on large screens (>=768px) | ||
| - [ ] Toggle theme and verify `_grey_tabby` variants load | ||
| - [ ] Check that images look sharp and clear | ||
| - [ ] Resize window and verify images switch appropriately | ||
|
|
||
| ### Performance Testing | ||
| To measure actual bandwidth savings: | ||
| 1. Clear browser cache | ||
| 2. Open DevTools Network tab | ||
| 3. Navigate to a page with many images | ||
| 4. Check total transferred data | ||
| 5. Compare with expected sizes | ||
|
|
||
| ## Troubleshooting | ||
|
|
||
| ### Images Not Loading | ||
| If scaled images fail to load: | ||
| 1. Check browser console for 404 errors | ||
| 2. Verify scaled images exist in `public/` directory | ||
| 3. Run build and check `build/` directory for images | ||
| 4. Verify correct naming convention is used | ||
|
|
||
| ### Quality Issues | ||
| If images appear blurry or pixelated: | ||
| 1. Adjust quality setting in generation script | ||
| 2. Increase target size (e.g., 800px for desktop) | ||
| 3. Regenerate images with new settings | ||
|
|
||
| ### Theme Switch Issues | ||
| If dark mode images don't load: | ||
| 1. Verify `_grey_tabby` variants exist | ||
| 2. Check browser console for errors | ||
| 3. Test the `useThemeImage` hook directly | ||
|
|
||
| ## Future Improvements | ||
| Potential enhancements: | ||
| - [ ] Add WebP format support for better compression | ||
| - [ ] Implement lazy loading for off-screen images | ||
| - [ ] Add srcset/picture element support | ||
| - [ ] Create automated CI/CD image optimization pipeline | ||
| - [ ] Add visual regression testing | ||
|
|
||
| ## Related Files | ||
| - `scripts/generate-scaled-images.sh` - Image generation script | ||
| - `src/hooks/useThemeImage.js` - Responsive image selection hook | ||
| - `public/*.png` - Original and scaled images | ||
| - `.github/workflows/*.yml` - CI/CD configuration (future) | ||
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,120 @@ | ||||||||||||
| #!/bin/bash | ||||||||||||
|
|
||||||||||||
| # Script to generate scaled versions of large PNG images for desktop and mobile | ||||||||||||
| # Usage: ./scripts/generate-scaled-images.sh | ||||||||||||
|
|
||||||||||||
| set -e -o pipefail | ||||||||||||
|
|
||||||||||||
| # Colors for output | ||||||||||||
| RED='\033[0;31m' | ||||||||||||
| GREEN='\033[0;32m' | ||||||||||||
| YELLOW='\033[1;33m' | ||||||||||||
| NC='\033[0m' # No Color | ||||||||||||
|
|
||||||||||||
| echo "🖼️ Generating scaled image versions..." | ||||||||||||
| echo "" | ||||||||||||
|
|
||||||||||||
| # Target sizes | ||||||||||||
| DESKTOP_WIDTH=600 # For desktop displays (retina-ready at ~300px display) | ||||||||||||
| MOBILE_WIDTH=300 # For mobile displays (~150px display) | ||||||||||||
|
|
||||||||||||
| # Counter for processed images | ||||||||||||
| processed=0 | ||||||||||||
| skipped=0 | ||||||||||||
| errors=0 | ||||||||||||
|
|
||||||||||||
| # Find all PNG files larger than 200KB and store in array | ||||||||||||
| mapfile -t png_files < <(find public -name "*.png" -size +200k -type f | sort) | ||||||||||||
|
||||||||||||
| mapfile -t png_files < <(find public -name "*.png" -size +200k -type f | sort) | |
| png_files=() | |
| while IFS= read -r file; do | |
| png_files+=("$file") | |
| done < <(find public -name "*.png" -size +200k -type f | sort) |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The percentage calculation appears incorrect. The time reduction from 85s to 6s is approximately 93% reduction in time, not 93% faster. "93% faster" would mean the new time is 7% of the improvement, which doesn't match these numbers. Consider using "93% reduction in loading time" or "14x faster" for clarity.