diff --git a/Documentation/content/docs/gallery/GCodeReaderWithIcon.jpg b/Documentation/content/docs/gallery/GCodeReaderWithIcon.jpg
new file mode 100644
index 00000000000..70c5b3aa9d0
Binary files /dev/null and b/Documentation/content/docs/gallery/GCodeReaderWithIcon.jpg differ
diff --git a/Documentation/content/examples/index.md b/Documentation/content/examples/index.md
index 1207c49b9fa..f06c181c010 100644
--- a/Documentation/content/examples/index.md
+++ b/Documentation/content/examples/index.md
@@ -184,6 +184,7 @@ This will allow you to see the some live code running in your browser. Just pick
[![HttpDataSetSeriesReader Example][HttpDataSetSeriesReaderWithIcon]](./HttpDataSetSeriesReader.html "Import a VTK dataset with time support.")
[![HttpSceneLoader Example][HttpSceneLoaderWithIcon]](./HttpSceneLoader.html "Import a VTK scene (data + representation)")
[![OfflineLocalView Example][OfflineLocalViewWithIcon]](./OfflineLocalView.html "Load a serialized scene (VTKSZ)")
+[![G-Code Example][GCodeReaderWithIcon]](./GCodeReader.html "G-Code reader(gcode)")
@@ -203,6 +204,7 @@ This will allow you to see the some live code running in your browser. Just pick
[HttpDataSetSeriesReaderWithIcon]: ../docs/gallery/HttpDataSetSeriesReaderWithIcon.gif
[HttpSceneLoaderWithIcon]: ../docs/gallery/HttpSceneLoaderWithIcon.jpg
[OfflineLocalViewWithIcon]: ../docs/gallery/OfflineLocalViewWithIcon.jpg
+[GCodeReaderWithIcon]: ../docs/gallery/GCodeReaderWithIcon.jpg
# Actors
diff --git a/Sources/IO/Misc/GCodeReader/example/controller.html b/Sources/IO/Misc/GCodeReader/example/controller.html
new file mode 100644
index 00000000000..42f9ea66af5
--- /dev/null
+++ b/Sources/IO/Misc/GCodeReader/example/controller.html
@@ -0,0 +1,13 @@
+
+
+
+
Options
+
+
+
+
Layers:
+
+
+
+
+
diff --git a/Sources/IO/Misc/GCodeReader/example/index.js b/Sources/IO/Misc/GCodeReader/example/index.js
new file mode 100644
index 00000000000..eb921a9cb5f
--- /dev/null
+++ b/Sources/IO/Misc/GCodeReader/example/index.js
@@ -0,0 +1,137 @@
+import '@kitware/vtk.js/favicon';
+
+// Load the rendering pieces we want to use (for both WebGL and WebGPU)
+import '@kitware/vtk.js/Rendering/Profiles/Geometry';
+
+import vtkFullScreenRenderWindow from '@kitware/vtk.js/Rendering/Misc/FullScreenRenderWindow';
+import vtkActor from '@kitware/vtk.js/Rendering/Core/Actor';
+import vtkMapper from '@kitware/vtk.js/Rendering/Core/Mapper';
+import vtkGCodeReader from '@kitware/vtk.js/IO/Misc/GCodeReader';
+
+import controlPanel from './controller.html';
+
+// ----------------------------------------------------------------------------
+// Example code
+// ----------------------------------------------------------------------------
+
+let renderer = null;
+let renderWindow = null;
+let layersSelector = null;
+let layersLabel = null;
+
+const reader = vtkGCodeReader.newInstance();
+
+// ----------------------------------------------------------------------------
+
+function hslToRgb(h, s, l) {
+ let r;
+ let g;
+ let b;
+
+ if (s === 0) {
+ r = l;
+ g = l;
+ b = l;
+ } else {
+ const hue2rgb = (p, q, t) => {
+ let tMod = t;
+ if (tMod < 0) tMod += 1;
+ if (tMod > 1) tMod -= 1;
+ if (tMod < 1 / 6) return p + (q - p) * 6 * tMod;
+ if (tMod < 1 / 2) return q;
+ if (tMod < 2 / 3) return p + (q - p) * (2 / 3 - tMod) * 6;
+ return p;
+ };
+
+ const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
+ const p = 2 * l - q;
+ r = hue2rgb(p, q, h + 1 / 3);
+ g = hue2rgb(p, q, h);
+ b = hue2rgb(p, q, h - 1 / 3);
+ }
+
+ return [r, g, b];
+}
+
+function refresh() {
+ if (renderer && renderWindow) {
+ renderer.resetCamera();
+ renderWindow.render();
+ }
+}
+
+function update() {
+ const fullScreenRenderer = vtkFullScreenRenderWindow.newInstance();
+ fullScreenRenderer.addController(controlPanel);
+ layersSelector = document.querySelector('.layers');
+ layersLabel = document.querySelector('.label');
+ renderer = fullScreenRenderer.getRenderer();
+ renderWindow = fullScreenRenderer.getRenderWindow();
+ const numLayers = reader.getNumberOfOutputPorts();
+
+ layersLabel.innerHTML = `Layers(${numLayers}):`;
+ layersSelector.max = numLayers.toString();
+ layersSelector.value = numLayers.toString();
+
+ const actors = [];
+
+ for (let idx = 1; idx < numLayers; idx++) {
+ const polyData = reader.getOutputData(idx);
+ if (polyData) {
+ const mapper = vtkMapper.newInstance();
+ mapper.setInputData(polyData);
+
+ const actor = vtkActor.newInstance();
+ actor.setMapper(mapper);
+
+ const hue = (idx / numLayers) * 0.8; // Use 0.8 instead of 1.0 to avoid red wrapping
+ actor.getProperty().setColor(...hslToRgb(hue, 1, 0.5));
+ actor.rotateX(-90);
+
+ actors.push(actor);
+ }
+ }
+
+ layersSelector.addEventListener('input', (event) => {
+ const visibleLayers = parseInt(event.target.value, 10);
+ actors.forEach((actor, index) => {
+ actor.setVisibility(index < visibleLayers);
+ });
+ renderWindow.render();
+ });
+
+ actors.forEach((actor) => renderer.addActor(actor));
+ refresh();
+}
+
+// ----------------------------------------------------------------------------
+// Use a file reader to load a local file
+// ----------------------------------------------------------------------------
+
+const myContainer = document.querySelector('body');
+const fileContainer = document.createElement('div');
+fileContainer.innerHTML =
+ '