Skip to content

Conversation

DedeHai
Copy link
Collaborator

@DedeHai DedeHai commented Oct 5, 2025

replaces the pixel magic tool.
This implements a much more feature-rich and user friendly way of displaying images.

Features:

  • Display all images on the controller, will be displayed on the selected segment. If another segment already has an image being played, its unloaded (if warning is confirmed)
  • If not a gif, a warning is displayed and the image is loaded up for conversion, "use pixel magic tool" as an alternative, also those get a red frame
  • Button to automatically install pxmagic tool or switch to pxmagic if its already installed (fetches .gz file from github, uploads it to file system automatically)

Image conversion tool:

  • Upload any image that the browser supports (canvas)
  • Crop any area of that image, crop area can be resized by dragging the frame (includes mobile support).
  • Animated gifs are supported as well: frames are loaded, cropped and saved (uses 2.5k extra flash)
  • Image can be panned and zoomed for detailed work (no pinch zoom support to not bloat code)
  • Preview area of what the resulting image will look like.
  • Automatically adjusts output size to selected segment size but can be overriden
  • Background color: transparent PNGs will use the selected color.
  • "Dark pixel cutoff" to remove "almost black" pixels for a crisp display. Threshold can be set from "none" up to "everything". This can also be used to apply a background to non transparend images or to create transparency masks when using overlapping segments.
  • Input file name to store: warning if file already exists in file system.

MatrixToolDemo

Scrolling Text tool:

  • Simple UI to enter text and add all supported tokens with local controls for the FX.
image

Total additional flash usage: 2.5k

For consistency I also updated the button styling in style.css: it now also uses a hover action.

Took some inspiration from @Manut38 (https://github.com/Manut38/WLED-GifPlayer-UI)

Summary by CodeRabbit

  • New Features

    • Added Matrix Tool page: image/GIF gallery, upload, crop editor, preview, per-segment image controls, and scrolling text with tokens; GIF encode/decode support for uploads/playback.
  • UI Changes

    • Home button renamed to “Matrix Tool” and opens the new page; tab/back-to-controls behavior preserved.
  • Performance/Behavior

    • Matrix Tool uses a separate stylesheet (CSS not inlined) for cleaner loading.
  • Style

    • Buttons receive smooth hover transitions and shared stylesheet rules.

Copy link
Contributor

coderabbitai bot commented Oct 5, 2025

Walkthrough

Adds a new Matrix Tool web UI and GIF encoder/decoder, updates build script to emit matrixtool HTML (non-inlined CSS), wires a new server route, updates the homepage button to point to the Matrix Tool, and extracts/adjusts some styling.

Changes

Cohort / File(s) Summary of changes
Build pipeline updates
tools/cdata.js
Adds matrixtool to generated assets; introduces inlineCss parameter (default true); calls matrixtool generation with inlineCss = false; removes previous cpal HTML generation call.
Server routing / feature guards
wled00/wled_server.cpp
Changes PxMagic guard to #ifdef WLED_ENABLE_PXMAGIC; adds Matrix Tool include guarded by #ifndef WLED_DISABLE_MATRIXTOOL; registers route /matrixtool.htm to serve PAGE_matrixtool.
Matrix Tool frontend & GIF codec
wled00/data/matrixtool/matrixtool.htm, wled00/data/matrixtool/omggif.js
Adds full Matrix Tool UI (image gallery, crop editor, GIF handling, per-segment text controls, upload/delete, server interactions) and a new omggif.js implementing GifReader/GifWriter for GIF decode/encode.
Homepage link update
wled00/data/index.htm
Renames Pixel Magic Tool button to "Matrix Tool" and updates its link to /matrixtool.htm.
Styling extraction and tweaks
wled00/data/settings.htm, wled00/data/style.css
settings.htm imports style.css and removes several inline body/button styles; style.css adds button/.btn transition and hover rules.
PxMagic minor formatting
wled00/data/pxmagic/pxmagic.htm
Only a formatting/newline adjustment; no functional changes.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Suggested reviewers

  • willmmiles
  • Aircoookie

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title clearly summarizes the addition of a new WLED Matrix tool featuring both image and scrolling text interfaces. It concisely reflects the primary change without unnecessary details or noise. Team members scanning the history will immediately understand the main enhancement introduced by this PR.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
wled00/data/style.css (1)

39-51: Indent with tabs per project guideline.

New declarations must use tabs for indentation in wled00/data assets; the added lines currently use spaces.

Apply this diff:

-  transition: all 0.3s ease;
+	transition: all 0.3s ease;
 }
-button:hover, .btn:hover{
-  background:#555;
-  border-color:#555;
-}
+button:hover, .btn:hover{
+	background:#555;
+	border-color:#555;
+}

As per coding guidelines

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3562fa2 and b3458b9.

📒 Files selected for processing (8)
  • tools/cdata.js (3 hunks)
  • wled00/data/index.htm (1 hunks)
  • wled00/data/matrixtool/matrixtool.htm (1 hunks)
  • wled00/data/matrixtool/omggif.js (1 hunks)
  • wled00/data/pxmagic/pxmagic.htm (1 hunks)
  • wled00/data/settings.htm (1 hunks)
  • wled00/data/style.css (2 hunks)
  • wled00/wled_server.cpp (2 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
wled00/data/**/*.{htm,html,css,js}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use tabs for indentation in web files (.htm/.html/.css/.js) under wled00/data

Files:

  • wled00/data/style.css
  • wled00/data/matrixtool/omggif.js
  • wled00/data/matrixtool/matrixtool.htm
  • wled00/data/settings.htm
  • wled00/data/pxmagic/pxmagic.htm
  • wled00/data/index.htm
wled00/**/*.{cpp,h}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use spaces (2 per level) for all C++ source and header files

Files:

  • wled00/wled_server.cpp
🧠 Learnings (2)
📚 Learning: 2025-09-20T09:00:08.942Z
Learnt from: CR
PR: wled/WLED#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-09-20T09:00:08.942Z
Learning: Applies to wled00/html_*.h : DO NOT edit generated headers wled00/html_*.h

Applied to files:

  • wled00/wled_server.cpp
  • tools/cdata.js
📚 Learning: 2025-09-14T18:43:59.338Z
Learnt from: blazoncek
PR: wled/WLED#4932
File: wled00/data/cpal/cpal.htm:14-14
Timestamp: 2025-09-14T18:43:59.338Z
Learning: In WLED, static web pages like cpal.htm are served directly at the root URL level (e.g., "/cpal.htm") via handleStaticContent() from embedded page data, regardless of their physical source folder location in the repository. Relative script references like "common.js" resolve correctly from the served URL path, not the source file path.

Applied to files:

  • tools/cdata.js
🪛 Biome (2.1.2)
wled00/data/matrixtool/omggif.js

[error] 438-438: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)


[error] 464-464: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)


[error] 465-465: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)


[error] 466-466: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)


[error] 467-467: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)


[error] 468-468: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)


[error] 469-469: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)


[error] 470-470: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)


[error] 471-471: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)


[error] 472-472: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)


[error] 473-473: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)


[error] 474-474: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)


[error] 475-475: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)


[error] 483-483: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)


[error] 512-512: This code is unreachable

(lint/correctness/noUnreachable)


[error] 32-32: Shouldn't redeclare 'gopts'. Consider to delete it or rename it.

'gopts' is defined here:

(lint/suspicious/noRedeclare)


[error] 32-32: This variable is used before its declaration.

The variable is declared here:

(lint/correctness/noInvalidUseBeforeDeclaration)


[error] 32-32: This variable is used before its declaration.

The variable is declared here:

(lint/correctness/noInvalidUseBeforeDeclaration)


[error] 448-448: Shouldn't redeclare 'block_size'. Consider to delete it or rename it.

'block_size' is defined here:

(lint/suspicious/noRedeclare)


[error] 477-477: Shouldn't redeclare 'has_local_palette'. Consider to delete it or rename it.

'has_local_palette' is defined here:

(lint/suspicious/noRedeclare)


[error] 487-487: Shouldn't redeclare 'block_size'. Consider to delete it or rename it.

'block_size' is defined here:

(lint/suspicious/noRedeclare)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
  • GitHub Check: wled_build / Build Environments (usermods)
  • GitHub Check: wled_build / Build Environments (esp32_wrover)
  • GitHub Check: wled_build / Build Environments (esp32s3dev_8MB_opi)
  • GitHub Check: wled_build / Build Environments (esp32s3_4M_qspi)
  • GitHub Check: wled_build / Build Environments (esp32dev)
  • GitHub Check: wled_build / Build Environments (esp32_eth)
  • GitHub Check: wled_build / Build Environments (esp32s3dev_16MB_opi)
  • GitHub Check: wled_build / Build Environments (lolin_s2_mini)

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (7)
wled00/data/matrixtool/matrixtool.htm (7)

254-440: Consider accessibility enhancements.

The UI structure is well-organized. For better accessibility, consider adding ARIA labels to interactive elements and ensuring full keyboard navigation support for the cropping canvas and context menus.


467-491: Segment filtering correctly prevents NaN dimensions.

The implementation at lines 477-481 correctly filters out 1D segments (where h > 1 && w > 1 is false), which resolves the NaN dimension issue from previous discussions. The fallback values at line 489 (||16) provide safe defaults when segment data is missing.

Consider showing errors to users.

Line 490 catches errors with console.error, which logs to the console but doesn't notify the user. Consider using the toast() function to display fetch errors:

-	}).catch(console.error);
+	}).catch(e => { console.error(e); toast('Failed to load segments', 'error'); });

537-563: Consider parallelizing image loading.

The sequential image loading at lines 540-562 uses await inside a for...of loop, which loads images one at a time. For better performance, consider loading images in parallel:

-	for(const f of imgs){
+	await Promise.all(imgs.map(async (f) => {
 		const name=f.name.replace('/',''),url=`${wURL}/${name}`;
 		// ... rest of loading logic
-	}
+	}));

This will significantly improve load times when multiple images are present on the device.


786-799: Prefer toast() over alert() for consistency.

Line 788 uses alert() for the unsupported format message, which is inconsistent with the toast() pattern used elsewhere in the codebase. Consider refactoring:

 function showUnsupported(url,name){
-	const msg=`Image format not supported by WLED.\nPlease convert to GIF below or use the Pixel Magic Tool.`;
-	alert(msg);
+	toast('Image format not supported by WLED. Please convert to GIF below or use the Pixel Magic Tool.', 'error');
 	fetch(url)

This improves UI consistency and user experience.


959-976: Simplify shadow disabling.

Line 974 sets shadowColor to "#000F" (transparent) to disable the shadow effect. A clearer approach is to set shadowBlur to 0:

 	ctx.roundRect(crop.x, crop.y, crop.w, crop.h, 6);
 	ctx.stroke();
-	ctx.shadowColor = "#000F"; // disable shadow again by simply making it transparent
+	ctx.shadowBlur = 0;
+	ctx.shadowColor = "transparent";
 	updPrev();
 }

1139-1156: Consider using addEventListener for context menu.

Lines 1146-1148 use inline onclick attributes in the context menu HTML, which can cause CSP violations and reduces maintainability. Consider refactoring to event listeners:

 	menu.innerHTML=`
-		<button onclick="downloadImg()">Download</button>
-		<button class="danger" onclick="deleteImg()">Delete</button>
-		<button onclick="closeMenu()">Cancel</button>`;
+		<button data-action="download">Download</button>
+		<button class="danger" data-action="delete">Delete</button>
+		<button data-action="cancel">Cancel</button>`;
+	menu.querySelector('[data-action="download"]').onclick = downloadImg;
+	menu.querySelector('[data-action="delete"]').onclick = deleteImg;
+	menu.querySelector('[data-action="cancel"]').onclick = closeMenu;

1249-1255: Consider using named constants for effect IDs.

The code uses magic numbers for effect IDs (e.g., 53 for image, 122 for scrolling text) throughout the file. Consider defining named constants at the top of the script for better maintainability:

const FX_IMAGE = 53;
const FX_SCROLLING_TEXT = 122;

// Then use throughout:
function upTxt(){
	const id=+gId('segTxt').value,txt=gId('txtIn').value.trim().slice(0,64);
	const j={on:true,seg:{id,fx:FX_SCROLLING_TEXT,n:txt,...}};

This makes the code more self-documenting and easier to maintain if effect IDs change.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b3458b9 and 15eb30a.

📒 Files selected for processing (1)
  • wled00/data/matrixtool/matrixtool.htm (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
wled00/data/**/*.{htm,html,css,js}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use tabs for indentation in web files (.htm/.html/.css/.js) under wled00/data

Files:

  • wled00/data/matrixtool/matrixtool.htm
wled00/data/**

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

wled00/data/**: When modifying web UI files, run npm run build to regenerate embedded headers before any firmware build
For web UI changes, edit files only under wled00/data (not firmware or generated files)

Files:

  • wled00/data/matrixtool/matrixtool.htm
🧠 Learnings (2)
📚 Learning: 2025-10-05T15:41:15.790Z
Learnt from: DedeHai
PR: wled/WLED#4982
File: wled00/data/matrixtool/omggif.js:32-35
Timestamp: 2025-10-05T15:41:15.790Z
Learning: The file `wled00/data/matrixtool/omggif.js` is an external third-party library from https://github.com/deanm/omggif by Dean McNamee and should not be reviewed for code issues as it's maintained externally.

Applied to files:

  • wled00/data/matrixtool/matrixtool.htm
📚 Learning: 2025-10-05T15:24:05.535Z
Learnt from: CR
PR: wled/WLED#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-05T15:24:05.535Z
Learning: Applies to wled00/data/**/*.{htm,html,css,js} : Use tabs for indentation in web files (.htm/.html/.css/.js) under wled00/data

Applied to files:

  • wled00/data/matrixtool/matrixtool.htm
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (18)
  • GitHub Check: wled_build / Build Environments (esp32c3dev)
  • GitHub Check: wled_build / Build Environments (lolin_s2_mini)
  • GitHub Check: wled_build / Build Environments (esp32s3dev_8MB_opi)
  • GitHub Check: wled_build / Build Environments (esp32s3_4M_qspi)
  • GitHub Check: wled_build / Build Environments (esp32s3dev_16MB_opi)
  • GitHub Check: wled_build / Build Environments (esp32_wrover)
  • GitHub Check: wled_build / Build Environments (usermods)
  • GitHub Check: wled_build / Build Environments (esp32_eth)
  • GitHub Check: wled_build / Build Environments (esp32dev)
  • GitHub Check: wled_build / Build Environments (esp01_1m_full_compat)
  • GitHub Check: wled_build / Build Environments (esp8266_2m_compat)
  • GitHub Check: wled_build / Build Environments (esp8266_2m_160)
  • GitHub Check: wled_build / Build Environments (esp01_1m_full_160)
  • GitHub Check: wled_build / Build Environments (nodemcuv2_compat)
  • GitHub Check: wled_build / Build Environments (esp01_1m_full)
  • GitHub Check: wled_build / Build Environments (nodemcuv2_160)
  • GitHub Check: wled_build / Build Environments (nodemcuv2)
  • GitHub Check: wled_build / Build Environments (esp8266_2m)
🔇 Additional comments (1)
wled00/data/matrixtool/matrixtool.htm (1)

1-253: LGTM!

The HTML structure and CSS styling are well-organized. The tab indentation follows the project guidelines for web assets under wled00/data. The styling provides a comprehensive and polished UI for the Matrix Tool.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (3)
wled00/data/matrixtool/matrixtool.htm (3)

712-712: Consider adding clarifying comment for delay conversion.

The 10 multiplier converts GIF centiseconds to milliseconds, and 50 sets a reasonable minimum. A brief comment would help future maintainers.

Apply this diff:

 const avg=gF.reduce((s,f)=>s+f.delay,0)/gF.length;
-aT=setInterval(step,Math.max(avg*10,50));
+// GIF delays are in centiseconds; convert to ms with 50ms minimum
+aT=setInterval(step,Math.max(avg*10,50));

956-975: Consider using a more sophisticated color quantization algorithm.

The current bit-reduction approach works but may produce poor results for images with many colors. A median-cut or octree quantization would preserve colors better.

The current implementation is functional for a simple tool, but if image quality is important, consider implementing median-cut quantization or using a library. The current approach progressively drops LSBs which can cause significant banding in gradients.

Example libraries:

  • RgbQuant.js
  • quantize.js

However, this would add dependency size, so only consider if image quality issues are reported.


878-878: Use more precise regex for hex color parsing.

The pattern /\w\w/g matches any two word characters, but /[0-9a-fA-F]{2}/g more precisely matches hex digits. While color inputs are browser-controlled, the more specific pattern is technically more correct.

Apply this diff:

 let t=+gId('bt').value,
   dt=c.getImageData(0,0,c.canvas.width,c.canvas.height),
-  b=gId('bg').value.match(/\w\w/g).map(x=>parseInt(x,16));
+  b=gId('bg').value.match(/[0-9a-fA-F]{2}/g).map(x=>parseInt(x,16));
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 15eb30a and de942ad.

📒 Files selected for processing (1)
  • wled00/data/matrixtool/matrixtool.htm (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
wled00/data/**/*.{htm,html,css,js}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use tabs for indentation in web files (.htm/.html/.css/.js) under wled00/data

Files:

  • wled00/data/matrixtool/matrixtool.htm
wled00/data/**

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

wled00/data/**: When modifying web UI files, run npm run build to regenerate embedded headers before any firmware build
For web UI changes, edit files only under wled00/data (not firmware or generated files)

Files:

  • wled00/data/matrixtool/matrixtool.htm
🧠 Learnings (2)
📚 Learning: 2025-10-05T15:41:15.790Z
Learnt from: DedeHai
PR: wled/WLED#4982
File: wled00/data/matrixtool/omggif.js:32-35
Timestamp: 2025-10-05T15:41:15.790Z
Learning: The file `wled00/data/matrixtool/omggif.js` is an external third-party library from https://github.com/deanm/omggif by Dean McNamee and should not be reviewed for code issues as it's maintained externally.

Applied to files:

  • wled00/data/matrixtool/matrixtool.htm
📚 Learning: 2025-10-05T15:24:05.535Z
Learnt from: CR
PR: wled/WLED#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-10-05T15:24:05.535Z
Learning: Applies to wled00/data/**/*.{htm,html,css,js} : Use tabs for indentation in web files (.htm/.html/.css/.js) under wled00/data

Applied to files:

  • wled00/data/matrixtool/matrixtool.htm
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (17)
  • GitHub Check: wled_build / Build Environments (esp32s3_4M_qspi)
  • GitHub Check: wled_build / Build Environments (lolin_s2_mini)
  • GitHub Check: wled_build / Build Environments (esp32dev)
  • GitHub Check: wled_build / Build Environments (usermods)
  • GitHub Check: wled_build / Build Environments (esp32_eth)
  • GitHub Check: wled_build / Build Environments (esp32s3dev_16MB_opi)
  • GitHub Check: wled_build / Build Environments (esp32_wrover)
  • GitHub Check: wled_build / Build Environments (esp32c3dev)
  • GitHub Check: wled_build / Build Environments (esp32s3dev_8MB_opi)
  • GitHub Check: wled_build / Build Environments (esp01_1m_full_compat)
  • GitHub Check: wled_build / Build Environments (esp8266_2m_160)
  • GitHub Check: wled_build / Build Environments (esp8266_2m_compat)
  • GitHub Check: wled_build / Build Environments (nodemcuv2_compat)
  • GitHub Check: wled_build / Build Environments (nodemcuv2_160)
  • GitHub Check: wled_build / Build Environments (esp8266_2m)
  • GitHub Check: wled_build / Build Environments (esp01_1m_full_160)
  • GitHub Check: wled_build / Build Environments (esp01_1m_full)
🔇 Additional comments (5)
wled00/data/matrixtool/matrixtool.htm (5)

469-477: Segment filtering correctly prevents NaN dimensions.

The check if(h>1&&w>1) properly filters out 1D segments and prevents NaN values from being stored in the dataset, as the dataset assignments are inside the conditional block.


697-713: GIF animation logic is well-structured.

The function properly handles edge cases (no frames, single frame), clears existing intervals before starting new ones, and uses a sensible minimum frame delay to prevent excessive CPU usage.


640-668: GIF disposal handling correctly implements the GIF89a spec.

The frame-by-frame decoding properly handles disposal modes:

  • Mode 2: Restore to background (line 660)
  • Mode 3: Restore to previous frame (line 661)

This ensures animated GIFs display correctly even with complex disposal requirements.


984-1005: Image playback correctly handles segment conflicts.

The function detects when another segment is showing an image and prompts the user before switching. The conditional payload construction (lines 993-995) ensures the old segment is properly cleared (fx=0) when switching.


1072-1082: Token insertion properly handles edge cases.

The function correctly preserves cursor position, respects the 64-character limit, and handles missing selection positions with nullish coalescing. The Math.min ensures the cursor doesn't overflow the string length.

Comment on lines +899 to +900
const w=+gId('w').value,h=+gId('h').value,fn=gId('fn').value.trim()||'image';
const filename=`${fn}.gif`;
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Sanitize user-provided filename to prevent path traversal.

The filename is constructed from user input without sanitization. While the server should validate, client-side sanitization provides defense-in-depth against path traversal attempts.

Apply this diff to sanitize the filename:

 const w=+gId('w').value,h=+gId('h').value,fn=gId('fn').value.trim()||'image';
-const filename=`${fn}.gif`;
+// Sanitize filename: remove path separators and limit to safe characters
+const safeFn = fn.replace(/[^a-zA-Z0-9_-]/g, '_').substring(0, 26);
+const filename=`${safeFn}.gif`;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const w=+gId('w').value,h=+gId('h').value,fn=gId('fn').value.trim()||'image';
const filename=`${fn}.gif`;
const w = +gId('w').value,
h = +gId('h').value,
fn = gId('fn').value.trim() || 'image';
// Sanitize filename: remove path separators and limit to safe characters
const safeFn = fn.replace(/[^a-zA-Z0-9_-]/g, '_').substring(0, 26);
const filename = `${safeFn}.gif`;
🤖 Prompt for AI Agents
In wled00/data/matrixtool/matrixtool.htm around lines 899-900, the code builds
filename from user input without sanitization, allowing path traversal or
malformed names; sanitize the user-provided fn by removing any path separators
and traversal tokens (e.g., strip slashes and backslashes, remove any "../" or
"..\" sequences), allow only a safe subset of characters (e.g., letters, digits,
hyphen, underscore), collapse multiple dots so only a single basename remains,
fall back to 'image' if the sanitized name is empty, then append the fixed
'.gif' extension; ensure the resulting filename contains no directory components
and contains only the allowed characters before assigning to filename.

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

Successfully merging this pull request may close these issues.

3 participants