diff --git a/src/Artemis.VisualScripting/Artemis.VisualScripting.csproj b/src/Artemis.VisualScripting/Artemis.VisualScripting.csproj
index e90cdc711..4d1340e9f 100644
--- a/src/Artemis.VisualScripting/Artemis.VisualScripting.csproj
+++ b/src/Artemis.VisualScripting/Artemis.VisualScripting.csproj
@@ -16,7 +16,6 @@
-
@@ -26,6 +25,9 @@
+
+ QuantizeNodeCustomView.axaml
+
EasingTypeNodeEasingView.axaml
diff --git a/src/Artemis.VisualScripting/Nodes/Color/QuantizeNode.cs b/src/Artemis.VisualScripting/Nodes/Color/QuantizeNode.cs
new file mode 100644
index 000000000..9407f8e6f
--- /dev/null
+++ b/src/Artemis.VisualScripting/Nodes/Color/QuantizeNode.cs
@@ -0,0 +1,68 @@
+using Artemis.Core;
+using Artemis.Core.Services;
+using Artemis.VisualScripting.Nodes.Color.Screens;
+using SkiaSharp;
+
+namespace Artemis.VisualScripting.Nodes.Color;
+
+public class QuantizeNodeStorage
+{
+ public int PaletteSize { get; set; } = 32;
+ public bool IgnoreLimits { get; set; }
+};
+
+[Node("Quantize", "Quantizes the image into key-colors", "Image", InputType = typeof(SKBitmap), OutputType = typeof(SKColor))]
+public class QuantizeNode : Node
+{
+ #region Properties & Fields
+
+ public InputPin Image { get; set; }
+
+ public OutputPin Vibrant { get; set; }
+ public OutputPin Muted { get; set; }
+ public OutputPin DarkVibrant { get; set; }
+ public OutputPin DarkMuted { get; set; }
+ public OutputPin LightVibrant { get; set; }
+ public OutputPin LightMuted { get; set; }
+
+ #endregion
+
+ #region Constructors
+
+ public QuantizeNode()
+ : base("Quantize", "Quantizes the image into key-colors")
+ {
+ Image = CreateInputPin("Image");
+
+ Vibrant = CreateOutputPin("Vibrant");
+ Muted = CreateOutputPin("Muted");
+ DarkVibrant = CreateOutputPin("DarkVibrant");
+ DarkMuted = CreateOutputPin("DarkMuted");
+ LightVibrant = CreateOutputPin("LightVibrant");
+ LightMuted = CreateOutputPin("LightMuted");
+
+ Storage = new QuantizeNodeStorage();
+ }
+
+ #endregion
+
+ #region Methods
+
+ public override void Evaluate()
+ {
+ SKBitmap? image = Image.Value;
+ if (image == null) return;
+
+ SKColor[] colorPalette = ColorQuantizer.Quantize(image.Pixels, Storage?.PaletteSize ?? 32);
+ ColorSwatch swatch = ColorQuantizer.FindAllColorVariations(colorPalette, Storage?.IgnoreLimits ?? false);
+
+ Vibrant.Value = swatch.Vibrant;
+ Muted.Value = swatch.Muted;
+ DarkVibrant.Value = swatch.DarkVibrant;
+ DarkMuted.Value = swatch.DarkMuted;
+ LightVibrant.Value = swatch.LightVibrant;
+ LightMuted.Value = swatch.LightMuted;
+ }
+
+ #endregion
+}
\ No newline at end of file
diff --git a/src/Artemis.VisualScripting/Nodes/Color/Screens/QuantizeNodeCustomView.axaml b/src/Artemis.VisualScripting/Nodes/Color/Screens/QuantizeNodeCustomView.axaml
new file mode 100644
index 000000000..aacb06b12
--- /dev/null
+++ b/src/Artemis.VisualScripting/Nodes/Color/Screens/QuantizeNodeCustomView.axaml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Artemis.VisualScripting/Nodes/Color/Screens/QuantizeNodeCustomView.axaml.cs b/src/Artemis.VisualScripting/Nodes/Color/Screens/QuantizeNodeCustomView.axaml.cs
new file mode 100644
index 000000000..82dd41275
--- /dev/null
+++ b/src/Artemis.VisualScripting/Nodes/Color/Screens/QuantizeNodeCustomView.axaml.cs
@@ -0,0 +1,17 @@
+using Avalonia.Markup.Xaml;
+using Avalonia.ReactiveUI;
+
+namespace Artemis.VisualScripting.Nodes.Color.Screens;
+
+public partial class QuantizeNodeCustomView : ReactiveUserControl
+{
+ public QuantizeNodeCustomView()
+ {
+ InitializeComponent();
+ }
+
+ private void InitializeComponent()
+ {
+ AvaloniaXamlLoader.Load(this);
+ }
+}
\ No newline at end of file
diff --git a/src/Artemis.VisualScripting/Nodes/Color/Screens/QuantizeNodeCustomViewModel.cs b/src/Artemis.VisualScripting/Nodes/Color/Screens/QuantizeNodeCustomViewModel.cs
new file mode 100644
index 000000000..398f0058d
--- /dev/null
+++ b/src/Artemis.VisualScripting/Nodes/Color/Screens/QuantizeNodeCustomViewModel.cs
@@ -0,0 +1,58 @@
+using System.Collections.ObjectModel;
+using Artemis.Core;
+using Artemis.UI.Shared.Services.NodeEditor;
+using Artemis.UI.Shared.Services.NodeEditor.Commands;
+using Artemis.UI.Shared.VisualScripting;
+using ReactiveUI;
+
+namespace Artemis.VisualScripting.Nodes.Color.Screens;
+
+public class QuantizeNodeCustomViewModel : CustomNodeViewModel
+{
+ #region Properties & Fields
+
+ private readonly QuantizeNode _node;
+ private readonly INodeEditorService _nodeEditorService;
+
+ public ObservableCollection PaletteSizes { get; } = new() { 1, 2, 4, 8, 16, 32, 64, 128, 256, 512 };
+
+ public int PaletteSize
+ {
+ get => _node.Storage?.PaletteSize ?? 32;
+ set
+ {
+ if ((_node.Storage != null) && (_node.Storage.PaletteSize != value))
+ {
+ _node.Storage.PaletteSize = value;
+ _nodeEditorService.ExecuteCommand(Script, new UpdateStorage(_node, _node.Storage));
+ }
+ }
+ }
+
+ public bool IgnoreLimits
+ {
+ get => _node.Storage?.IgnoreLimits ?? false;
+ set
+ {
+ if ((_node.Storage != null) && (_node.Storage.IgnoreLimits != value))
+ {
+ _node.Storage.IgnoreLimits = value;
+ _nodeEditorService.ExecuteCommand(Script, new UpdateStorage(_node, _node.Storage));
+ }
+ }
+ }
+
+ #endregion
+
+ #region Constructors
+
+ public QuantizeNodeCustomViewModel(QuantizeNode node, INodeScript script, INodeEditorService nodeEditorService) : base(node, script)
+ {
+ this._node = node;
+ this._nodeEditorService = nodeEditorService;
+
+ NodeModified += (_, _) => this.RaisePropertyChanged(nameof(PaletteSize));
+ }
+
+ #endregion
+}
\ No newline at end of file
diff --git a/src/Artemis.VisualScripting/Nodes/Image/CaptureScreenNode.cs b/src/Artemis.VisualScripting/Nodes/Image/CaptureScreenNode.cs
deleted file mode 100644
index c91ed8cda..000000000
--- a/src/Artemis.VisualScripting/Nodes/Image/CaptureScreenNode.cs
+++ /dev/null
@@ -1,66 +0,0 @@
-using Artemis.Core;
-using Artemis.VisualScripting.Nodes.Image.Screens;
-using ScreenCapture.NET;
-using SkiaSharp;
-
-namespace Artemis.VisualScripting.Nodes.Image;
-
-[Node("Capture Screen", "Captures a region of the screen", "Image", OutputType = typeof(SKBitmap))]
-public class CaptureScreenNode : Node