diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,14 @@
+# Changelog for `dear-imgui-raw-knobs`
+
+All notable changes to this package will be documented in this file.
+
+The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
+and this project adheres to the
+[Haskell Package Versioning Policy](https://pvp.haskell.org/).
+
+## 1.0.0 - 2026-10-21
+
+Initial release.
+
+- Generated with dear_bindings `v0.26` against Dear ImGui `v1.93.0-docking`.
+- Bundles imgui-knobs at commit `6b4b592`.
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,26 @@
+Copyright 2026 IC Rainbow
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1.  Redistributions of source code must retain the above copyright notice, this
+    list of conditions and the following disclaimer.
+
+2.  Redistributions in binary form must reproduce the above copyright notice,
+    this list of conditions and the following disclaimer in the documentation
+    and/or other materials provided with the distribution.
+
+3.  Neither the name of the copyright holder nor the names of its contributors
+    may be used to endorse or promote products derived from this software
+    without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,5 @@
+# dear-imgui-raw-knobs
+
+Raw FFI bindings to [imgui-knobs], rotary knob widgets for Dear ImGui.
+
+[imgui-knobs]: https://github.com/altschuler/imgui-knobs
diff --git a/cbits/DearImGuiWrappers.cpp b/cbits/DearImGuiWrappers.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/DearImGuiWrappers.cpp
@@ -0,0 +1,3 @@
+// Generated by dear-bindings-ffi. Do not edit.
+#include "DearImGuiWrappers.h"
+
diff --git a/cbits/DearImGuiWrappers.h b/cbits/DearImGuiWrappers.h
new file mode 100644
--- /dev/null
+++ b/cbits/DearImGuiWrappers.h
@@ -0,0 +1,16 @@
+// Generated by dear-bindings-ffi. Do not edit.
+#ifndef DEAR_IMGUI_WRAPPERS_H
+#define DEAR_IMGUI_WRAPPERS_H
+
+#include "dcimgui_knobs.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/cbits/dcimgui_knobs.cpp b/cbits/dcimgui_knobs.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/dcimgui_knobs.cpp
@@ -0,0 +1,106 @@
+// THIS FILE HAS BEEN AUTO-GENERATED BY THE 'DEAR BINDINGS' GENERATOR.
+// **DO NOT EDIT DIRECTLY**
+// https://github.com/dearimgui/dear_bindings
+
+#include "imgui.h"
+#include "imgui-knobs.h"
+
+// Glue file consumed by dear_bindings at imgui-knobs-binding generation
+// time. The cimgui namespace wraps the C-shape header so the
+// generator can emit type aliases without colliding with the C++
+// API; pulling dcimgui.h into the same namespace promotes ImVec2
+// and friends from forward-declared (the dcimgui_knobs.h default) to
+// fully defined, which dcimgui_knobs.cpp needs for its by-value
+// argument/return shims.
+#define DEAR_BINDINGS_INTERNAL_GLUE_CODE
+namespace cimgui
+{
+#include "dcimgui.h"
+#include "dcimgui_knobs.h"
+}
+#undef DEAR_BINDINGS_INTERNAL_GLUE_CODE
+// By-value struct conversions
+
+static inline cimgui::ImVec2 ConvertFromCPP_ImVec2(const ::ImVec2& src)
+{
+    cimgui::ImVec2 dest;
+    dest.x = src.x;
+    dest.y = src.y;
+    return dest;
+}
+
+static inline ::ImVec2 ConvertToCPP_ImVec2(const cimgui::ImVec2& src)
+{
+    ::ImVec2 dest;
+    dest.x = src.x;
+    dest.y = src.y;
+    return dest;
+}
+
+static inline cimgui::ImVec4 ConvertFromCPP_ImVec4(const ::ImVec4& src)
+{
+    cimgui::ImVec4 dest;
+    dest.x = src.x;
+    dest.y = src.y;
+    dest.z = src.z;
+    dest.w = src.w;
+    return dest;
+}
+
+static inline ::ImVec4 ConvertToCPP_ImVec4(const cimgui::ImVec4& src)
+{
+    ::ImVec4 dest;
+    dest.x = src.x;
+    dest.y = src.y;
+    dest.z = src.z;
+    dest.w = src.w;
+    return dest;
+}
+
+static inline cimgui::ImTextureRef ConvertFromCPP_ImTextureRef(const ::ImTextureRef& src)
+{
+    cimgui::ImTextureRef dest;
+    dest._TexData = reinterpret_cast<cimgui::ImTextureData*>(src._TexData);
+    dest._TexID = src._TexID;
+    return dest;
+}
+
+static inline ::ImTextureRef ConvertToCPP_ImTextureRef(const cimgui::ImTextureRef& src)
+{
+    ::ImTextureRef dest;
+    dest._TexData = reinterpret_cast<::ImTextureData*>(src._TexData);
+    dest._TexID = src._TexID;
+    return dest;
+}
+
+static inline cimgui::ImColor ConvertFromCPP_ImColor(const ::ImColor& src)
+{
+    cimgui::ImColor dest;
+    dest.Value.x = src.Value.x;
+    dest.Value.y = src.Value.y;
+    dest.Value.z = src.Value.z;
+    dest.Value.w = src.Value.w;
+    return dest;
+}
+
+static inline ::ImColor ConvertToCPP_ImColor(const cimgui::ImColor& src)
+{
+    ::ImColor dest;
+    dest.Value.x = src.Value.x;
+    dest.Value.y = src.Value.y;
+    dest.Value.z = src.Value.z;
+    dest.Value.w = src.Value.w;
+    return dest;
+}
+
+// Function stubs
+
+CIMGUI_API bool cimgui::ImGuiKnobsKnob(const char* label, float* p_value, float v_min, float v_max, float speed, const char* format, ImGuiKnobVariant variant, float size, ImGuiKnobFlags flags, int steps, float angle_min, float angle_max)
+{
+    return ::ImGuiKnobs::Knob(label, p_value, v_min, v_max, speed, format, variant, size, flags, steps, angle_min, angle_max);
+}
+
+CIMGUI_API bool cimgui::ImGuiKnobsKnobInt(const char* label, int* p_value, int v_min, int v_max, float speed, const char* format, ImGuiKnobVariant variant, float size, ImGuiKnobFlags flags, int steps, float angle_min, float angle_max)
+{
+    return ::ImGuiKnobs::KnobInt(label, p_value, v_min, v_max, speed, format, variant, size, flags, steps, angle_min, angle_max);
+}
diff --git a/cbits/dcimgui_knobs.h b/cbits/dcimgui_knobs.h
new file mode 100644
--- /dev/null
+++ b/cbits/dcimgui_knobs.h
@@ -0,0 +1,49 @@
+// THIS FILE HAS BEEN AUTO-GENERATED BY THE 'DEAR BINDINGS' GENERATOR.
+// **DO NOT EDIT DIRECTLY**
+// https://github.com/dearimgui/dear_bindings
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+// ImDrawIdx: vertex index. [Compile-time configurable type]
+// - To use 16-bit indices + allow large meshes: backend need to set 'io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset' and handle ImDrawCmd::VtxOffset (recommended).
+// - To use 32-bit indices: override with '#define ImDrawIdx unsigned int' in your imconfig.h file.
+#ifndef ImDrawIdx
+typedef unsigned short ImDrawIdx;  // Default: 16-bit (for maximum compatibility with renderer backends)
+#endif // #ifndef ImDrawIdx
+
+#include "dcimgui.h"
+typedef int ImGuiKnobFlags;
+
+typedef enum
+{
+    ImGuiKnobFlags_NoTitle        = 1<<0,
+    ImGuiKnobFlags_NoInput        = 1<<1,
+    ImGuiKnobFlags_ValueTooltip   = 1<<2,
+    ImGuiKnobFlags_DragHorizontal = 1<<3,
+    ImGuiKnobFlags_DragVertical   = 1<<4,
+    ImGuiKnobFlags_Logarithmic    = 1<<5,
+    ImGuiKnobFlags_AlwaysClamp    = 1<<6,
+} ImGuiKnobFlags_;
+
+typedef int ImGuiKnobVariant;
+
+typedef enum
+{
+    ImGuiKnobVariant_Tick      = 1<<0,
+    ImGuiKnobVariant_Dot       = 1<<1,
+    ImGuiKnobVariant_Wiper     = 1<<2,
+    ImGuiKnobVariant_WiperOnly = 1<<3,
+    ImGuiKnobVariant_WiperDot  = 1<<4,
+    ImGuiKnobVariant_Stepped   = 1<<5,
+    ImGuiKnobVariant_Space     = 1<<6,
+} ImGuiKnobVariant_;
+
+CIMGUI_API bool ImGuiKnobsKnob(const char* label, float* p_value, float v_min, float v_max, float speed /* = 0 */, const char* format /* = "%.3f" */, ImGuiKnobVariant variant /* = ImGuiKnobVariant_Tick */, float size /* = 0 */, ImGuiKnobFlags flags /* = 0 */, int steps /* = 10 */, float angle_min /* = -1 */, float angle_max /* = -1 */);
+CIMGUI_API bool ImGuiKnobsKnobInt(const char* label, int* p_value, int v_min, int v_max, float speed /* = 0 */, const char* format /* = "%i" */, ImGuiKnobVariant variant /* = ImGuiKnobVariant_Tick */, float size /* = 0 */, ImGuiKnobFlags flags /* = 0 */, int steps /* = 10 */, float angle_min /* = -1 */, float angle_max /* = -1 */);
+#ifdef __cplusplus
+} // End of extern "C" block
+#endif
diff --git a/cbits/imgui-knobs/imgui-knobs.cpp b/cbits/imgui-knobs/imgui-knobs.cpp
new file mode 100644
--- /dev/null
+++ b/cbits/imgui-knobs/imgui-knobs.cpp
@@ -0,0 +1,404 @@
+#include "imgui-knobs.h"
+
+#include <cmath>
+#include <cstdlib>
+#include <imgui.h>
+#include <imgui_internal.h>
+
+#define IMGUIKNOBS_PI 3.14159265358979323846f
+
+static inline float ImLog(int x) { return ImLog(static_cast<float>(x)); }
+
+namespace ImGuiKnobs {
+    namespace detail {
+        void draw_arc(ImVec2 center, float radius, float start_angle, float end_angle, float thickness, ImColor color) {
+            auto *draw_list = ImGui::GetWindowDrawList();
+
+            draw_list->PathArcTo(center, radius, start_angle, end_angle);
+#if IMGUI_VERSION_NUM < 19276
+            draw_list->PathStroke(color, 0, thickness);
+#else
+            draw_list->PathStroke(color,thickness);
+#endif
+        }
+
+        template<typename DataType>
+        struct knob {
+            float radius;
+            bool value_changed;
+            ImVec2 center;
+            bool is_active;
+            bool is_hovered;
+            float angle_min;
+            float angle_max;
+            float t;
+            float angle;
+            float angle_cos;
+            float angle_sin;
+
+            knob(const char *_label,
+                 ImGuiDataType data_type,
+                 DataType *p_value,
+                 DataType v_min,
+                 DataType v_max,
+                 float speed,
+                 float _radius,
+                 const char *format,
+                 ImGuiKnobFlags flags,
+                 float _angle_min,
+                 float _angle_max) {
+                radius = _radius;
+                if (flags & ImGuiKnobFlags_Logarithmic) {
+                    float v = ImMax(ImMin(*p_value, v_max), v_min);
+                    t = (ImLog(ImAbs(v)) - ImLog(ImAbs(v_min))) / (ImLog(ImAbs(v_max)) - ImLog(ImAbs(v_min)));
+                } else {
+                    t = ((float) *p_value - v_min) / (v_max - v_min);
+                }
+                auto screen_pos = ImGui::GetCursorScreenPos();
+
+                // Handle dragging
+                ImGui::InvisibleButton(_label, {radius * 2.0f, radius * 2.0f});
+
+                // Handle drag: if DragVertical or DragHorizontal flags are set, only the given direction is
+                // used, otherwise use the drag direction with the highest delta
+                ImGuiIO &io = ImGui::GetIO();
+                bool drag_vertical =
+                        !(flags & ImGuiKnobFlags_DragHorizontal) &&
+                        (flags & ImGuiKnobFlags_DragVertical || ImAbs(io.MouseDelta[ImGuiAxis_Y]) > ImAbs(io.MouseDelta[ImGuiAxis_X]));
+
+                auto gid = ImGui::GetID(_label);
+                ImGuiSliderFlags drag_behaviour_flags = 0;
+                if (drag_vertical) {
+                    drag_behaviour_flags |= ImGuiSliderFlags_Vertical;
+                }
+                if (flags & ImGuiKnobFlags_AlwaysClamp) {
+                    drag_behaviour_flags |= ImGuiSliderFlags_AlwaysClamp;
+                }
+                if (flags & ImGuiKnobFlags_Logarithmic) {
+                    drag_behaviour_flags |= ImGuiSliderFlags_Logarithmic;
+                }
+                value_changed = ImGui::DragBehavior(
+                        gid,
+                        data_type,
+                        p_value,
+                        speed,
+                        &v_min,
+                        &v_max,
+                        format,
+                        drag_behaviour_flags);
+
+                angle_min = _angle_min < 0 ? IMGUIKNOBS_PI * 0.75f : _angle_min;
+                angle_max = _angle_max < 0 ? IMGUIKNOBS_PI * 2.25f : _angle_max;
+
+                center = {screen_pos[0] + radius, screen_pos[1] + radius};
+                is_active = ImGui::IsItemActive();
+                is_hovered = ImGui::IsItemHovered();
+                angle = angle_min + (angle_max - angle_min) * t;
+                angle_cos = cosf(angle);
+                angle_sin = sinf(angle);
+            }
+
+            void draw_dot(float size, float radius, float angle, color_set color, bool filled, int segments) {
+                auto dot_size = size * this->radius;
+                auto dot_radius = radius * this->radius;
+
+                ImGui::GetWindowDrawList()->AddCircleFilled(
+                        {center[0] + cosf(angle) * dot_radius,
+                         center[1] + sinf(angle) * dot_radius},
+                        dot_size,
+                        is_active ? color.active : (is_hovered ? color.hovered : color.base),
+                        segments);
+            }
+
+            void draw_tick(float start, float end, float width, float angle, color_set color) {
+                auto tick_start = start * radius;
+                auto tick_end = end * radius;
+                auto angle_cos = cosf(angle);
+                auto angle_sin = sinf(angle);
+
+                ImGui::GetWindowDrawList()->AddLine(
+                        {center[0] + angle_cos * tick_end, center[1] + angle_sin * tick_end},
+                        {center[0] + angle_cos * tick_start,
+                         center[1] + angle_sin * tick_start},
+                        is_active ? color.active : (is_hovered ? color.hovered : color.base),
+                        width * radius);
+            }
+
+            void draw_circle(float size, color_set color, bool filled, int segments) {
+                auto circle_radius = size * radius;
+
+                ImGui::GetWindowDrawList()->AddCircleFilled(
+                        center,
+                        circle_radius,
+                        is_active ? color.active : (is_hovered ? color.hovered : color.base));
+            }
+
+            void draw_arc(float radius, float size, float start_angle, float end_angle, color_set color) {
+                auto track_radius = radius * this->radius;
+                auto track_size = size * this->radius * 0.5f + 0.0001f;
+
+                detail::draw_arc(center, track_radius, start_angle, end_angle, track_size, is_active ? color.active : (is_hovered ? color.hovered : color.base));
+            }
+        };
+
+        template<typename DataType>
+        knob<DataType> knob_with_drag(
+                const char *label,
+                ImGuiDataType data_type,
+                DataType *p_value,
+                DataType v_min,
+                DataType v_max,
+                float _speed,
+                const char *format,
+                float size,
+                ImGuiKnobFlags flags,
+                float angle_min,
+                float angle_max) {
+            if (flags & ImGuiKnobFlags_Logarithmic && v_min <= 0.0 && v_max >= 0.0) {
+                // we must handle the cornercase if a client specifies a logarithmic range that contains zero
+                // for this we clamp lower limit to avoid hitting zero like it is done in ImGui::SliderBehaviorT
+                const bool is_floating_point = (data_type == ImGuiDataType_Float) || (data_type == ImGuiDataType_Double);
+                const int decimal_precision = is_floating_point ? ImParseFormatPrecision(format, 3) : 1;
+                v_min = ImPow(0.1f, (float) decimal_precision);
+                v_max = ImMax(v_min, v_max); // this ensures that in the cornercase v_max is still at least ge v_min
+                *p_value = ImMax(ImMin(*p_value, v_max), v_min); // this ensures that in the cornercase p_value is within the range
+            }
+
+            auto speed = _speed == 0 ? (v_max - v_min) / 250.f : _speed;
+            ImGui::PushID(label);
+
+#if IMGUI_VERSION_NUM < 19197
+            auto font_scale = ImGui::GetIO().FontGlobalScale;
+#else
+            auto font_scale = ImGui::GetStyle().FontScaleMain;
+#endif
+            auto width = size == 0 ? ImGui::GetTextLineHeight() * 4.0f : size * font_scale;
+            ImGui::PushItemWidth(width);
+
+            ImGui::BeginGroup();
+
+            // There's an issue with `SameLine` and Groups, see
+            // https://github.com/ocornut/imgui/issues/4190. This is probably not the best
+            // solution, but seems to work for now
+            ImGui::GetCurrentWindow()->DC.CurrLineTextBaseOffset = 0;
+
+            // Draw title
+            if (!(flags & ImGuiKnobFlags_NoTitle)) {
+                auto title_size = ImGui::CalcTextSize(label, NULL, false, width);
+
+                // Center title
+                ImGui::SetCursorPosX(ImGui::GetCursorPosX() +
+                                     (width - title_size[0]) * 0.5f);
+
+                ImGui::Text("%s", label);
+            }
+
+            // Draw knob
+            knob<DataType> k(label, data_type, p_value, v_min, v_max, speed, width * 0.5f, format, flags, angle_min, angle_max);
+
+            // Draw tooltip
+            if (flags & ImGuiKnobFlags_ValueTooltip &&
+                (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled) ||
+                 ImGui::IsItemActive())) {
+                ImGui::BeginTooltip();
+                ImGui::Text(format, *p_value);
+                ImGui::EndTooltip();
+            }
+
+            // Draw input
+            if (!(flags & ImGuiKnobFlags_NoInput)) {
+                ImGuiSliderFlags drag_scalar_flags = 0;
+                if (flags & ImGuiKnobFlags_AlwaysClamp) {
+                    drag_scalar_flags |= ImGuiSliderFlags_AlwaysClamp;
+                }
+                if (flags & ImGuiKnobFlags_Logarithmic) {
+                    drag_scalar_flags |= ImGuiSliderFlags_Logarithmic;
+                }
+                auto changed = ImGui::DragScalar("###knob_drag", data_type, p_value, speed, &v_min, &v_max, format, drag_scalar_flags);
+                if (changed) {
+                    k.value_changed = true;
+                }
+            }
+
+            ImGui::EndGroup();
+            ImGui::PopItemWidth();
+            ImGui::PopID();
+
+            return k;
+        }
+
+        color_set GetPrimaryColorSet() {
+            auto *colors = ImGui::GetStyle().Colors;
+
+            return {colors[ImGuiCol_ButtonActive], colors[ImGuiCol_ButtonHovered], colors[ImGuiCol_ButtonHovered]};
+        }
+
+        color_set GetSecondaryColorSet() {
+            auto *colors = ImGui::GetStyle().Colors;
+            auto active = ImVec4(colors[ImGuiCol_ButtonActive].x * 0.5f,
+                                 colors[ImGuiCol_ButtonActive].y * 0.5f,
+                                 colors[ImGuiCol_ButtonActive].z * 0.5f,
+                                 colors[ImGuiCol_ButtonActive].w);
+
+            auto hovered = ImVec4(colors[ImGuiCol_ButtonHovered].x * 0.5f,
+                                  colors[ImGuiCol_ButtonHovered].y * 0.5f,
+                                  colors[ImGuiCol_ButtonHovered].z * 0.5f,
+                                  colors[ImGuiCol_ButtonHovered].w);
+
+            return {active, hovered, hovered};
+        }
+
+        color_set GetTrackColorSet() {
+            auto *colors = ImGui::GetStyle().Colors;
+
+            return {colors[ImGuiCol_Button], colors[ImGuiCol_Button], colors[ImGuiCol_Button]};
+        }
+    }// namespace detail
+
+    template<typename DataType>
+    bool BaseKnob(
+            const char *label,
+            ImGuiDataType data_type,
+            DataType *p_value,
+            DataType v_min,
+            DataType v_max,
+            float speed,
+            const char *format,
+            ImGuiKnobVariant variant,
+            float size,
+            ImGuiKnobFlags flags,
+            int steps,
+            float angle_min,
+            float angle_max) {
+        auto knob = detail::knob_with_drag(
+                label,
+                data_type,
+                p_value,
+                v_min,
+                v_max,
+                speed,
+                format,
+                size,
+                flags,
+                angle_min,
+                angle_max);
+
+        switch (variant) {
+            case ImGuiKnobVariant_Tick: {
+                knob.draw_circle(0.85f, detail::GetSecondaryColorSet(), true, 32);
+                knob.draw_tick(0.5f, 0.85f, 0.08f, knob.angle, detail::GetPrimaryColorSet());
+                break;
+            }
+            case ImGuiKnobVariant_Dot: {
+                knob.draw_circle(0.85f, detail::GetSecondaryColorSet(), true, 32);
+                knob.draw_dot(0.12f, 0.6f, knob.angle, detail::GetPrimaryColorSet(), true, 12);
+                break;
+            }
+
+            case ImGuiKnobVariant_Wiper: {
+                knob.draw_circle(0.7f, detail::GetSecondaryColorSet(), true, 32);
+                knob.draw_arc(0.8f, 0.41f, knob.angle_min, knob.angle_max, detail::GetTrackColorSet());
+
+                if (knob.t > 0.01f) {
+                    knob.draw_arc(0.8f, 0.43f, knob.angle_min, knob.angle, detail::GetPrimaryColorSet());
+                }
+                break;
+            }
+            case ImGuiKnobVariant_WiperOnly: {
+                knob.draw_arc(0.8f, 0.41f, knob.angle_min, knob.angle_max, detail::GetTrackColorSet());
+
+                if (knob.t > 0.01) {
+                    knob.draw_arc(0.8f, 0.43f, knob.angle_min, knob.angle, detail::GetPrimaryColorSet());
+                }
+                break;
+            }
+            case ImGuiKnobVariant_WiperDot: {
+                knob.draw_circle(0.6f, detail::GetSecondaryColorSet(), true, 32);
+                knob.draw_arc(0.85f, 0.41f, knob.angle_min, knob.angle_max, detail::GetTrackColorSet());
+                knob.draw_dot(0.1f, 0.85f, knob.angle, detail::GetPrimaryColorSet(), true, 12);
+                break;
+            }
+            case ImGuiKnobVariant_Stepped: {
+                for (auto n = 0.f; n < steps; n++) {
+                    auto a = n / (steps - 1);
+                    auto angle = knob.angle_min + (knob.angle_max - knob.angle_min) * a;
+                    knob.draw_tick(0.7f, 0.9f, 0.04f, angle, detail::GetPrimaryColorSet());
+                }
+
+                knob.draw_circle(0.6f, detail::GetSecondaryColorSet(), true, 32);
+                knob.draw_dot(0.12f, 0.4f, knob.angle, detail::GetPrimaryColorSet(), true, 12);
+                break;
+            }
+            case ImGuiKnobVariant_Space: {
+                knob.draw_circle(0.3f - knob.t * 0.1f, detail::GetSecondaryColorSet(), true, 16);
+
+                if (knob.t > 0.01f) {
+                    knob.draw_arc(0.4f, 0.15f, knob.angle_min - 1.0f, knob.angle - 1.0f, detail::GetPrimaryColorSet());
+                    knob.draw_arc(0.6f, 0.15f, knob.angle_min + 1.0f, knob.angle + 1.0f, detail::GetPrimaryColorSet());
+                    knob.draw_arc(0.8f, 0.15f, knob.angle_min + 3.0f, knob.angle + 3.0f, detail::GetPrimaryColorSet());
+                }
+                break;
+            }
+        }
+
+        return knob.value_changed;
+    }
+
+    bool Knob(
+            const char *label,
+            float *p_value,
+            float v_min,
+            float v_max,
+            float speed,
+            const char *format,
+            ImGuiKnobVariant variant,
+            float size,
+            ImGuiKnobFlags flags,
+            int steps,
+            float angle_min,
+            float angle_max) {
+        return BaseKnob(
+                label,
+                ImGuiDataType_Float,
+                p_value,
+                v_min,
+                v_max,
+                speed,
+                format,
+                variant,
+                size,
+                flags,
+                steps,
+                angle_min,
+                angle_max);
+    }
+
+    bool KnobInt(
+            const char *label,
+            int *p_value,
+            int v_min,
+            int v_max,
+            float speed,
+            const char *format,
+            ImGuiKnobVariant variant,
+            float size,
+            ImGuiKnobFlags flags,
+            int steps,
+            float angle_min,
+            float angle_max) {
+        return BaseKnob(
+                label,
+                ImGuiDataType_S32,
+                p_value,
+                v_min,
+                v_max,
+                speed,
+                format,
+                variant,
+                size,
+                flags,
+                steps,
+                angle_min,
+                angle_max);
+    }
+}// namespace ImGuiKnobs
diff --git a/cbits/imgui-knobs/imgui-knobs.h b/cbits/imgui-knobs/imgui-knobs.h
new file mode 100644
--- /dev/null
+++ b/cbits/imgui-knobs/imgui-knobs.h
@@ -0,0 +1,74 @@
+#pragma once
+
+#include <cstdlib>
+#include <imgui.h>
+
+typedef int ImGuiKnobFlags;
+
+enum ImGuiKnobFlags_ {
+    ImGuiKnobFlags_NoTitle = 1 << 0,
+    ImGuiKnobFlags_NoInput = 1 << 1,
+    ImGuiKnobFlags_ValueTooltip = 1 << 2,
+    ImGuiKnobFlags_DragHorizontal = 1 << 3,
+    ImGuiKnobFlags_DragVertical = 1 << 4,
+    ImGuiKnobFlags_Logarithmic = 1 << 5,
+    ImGuiKnobFlags_AlwaysClamp = 1 << 6
+};
+
+typedef int ImGuiKnobVariant;
+
+enum ImGuiKnobVariant_ {
+    ImGuiKnobVariant_Tick = 1 << 0,
+    ImGuiKnobVariant_Dot = 1 << 1,
+    ImGuiKnobVariant_Wiper = 1 << 2,
+    ImGuiKnobVariant_WiperOnly = 1 << 3,
+    ImGuiKnobVariant_WiperDot = 1 << 4,
+    ImGuiKnobVariant_Stepped = 1 << 5,
+    ImGuiKnobVariant_Space = 1 << 6,
+};
+
+namespace ImGuiKnobs {
+
+    struct color_set {
+        ImColor base;
+        ImColor hovered;
+        ImColor active;
+
+        color_set(ImColor base, ImColor hovered, ImColor active)
+            : base(base), hovered(hovered), active(active) {}
+
+        color_set(ImColor color) {
+            base = color;
+            hovered = color;
+            active = color;
+        }
+    };
+
+    bool Knob(
+            const char *label,
+            float *p_value,
+            float v_min,
+            float v_max,
+            float speed = 0,
+            const char *format = "%.3f",
+            ImGuiKnobVariant variant = ImGuiKnobVariant_Tick,
+            float size = 0,
+            ImGuiKnobFlags flags = 0,
+            int steps = 10,
+            float angle_min = -1,
+            float angle_max = -1);
+    bool KnobInt(
+            const char *label,
+            int *p_value,
+            int v_min,
+            int v_max,
+            float speed = 0,
+            const char *format = "%i",
+            ImGuiKnobVariant variant = ImGuiKnobVariant_Tick,
+            float size = 0,
+            ImGuiKnobFlags flags = 0,
+            int steps = 10,
+            float angle_min = -1,
+            float angle_max = -1);
+
+}// namespace ImGuiKnobs
diff --git a/dear-imgui-raw-knobs.cabal b/dear-imgui-raw-knobs.cabal
new file mode 100644
--- /dev/null
+++ b/dear-imgui-raw-knobs.cabal
@@ -0,0 +1,60 @@
+cabal-version: 2.2
+
+-- This file has been generated from package.yaml by hpack version 0.39.6.
+--
+-- see: https://github.com/sol/hpack
+
+name:           dear-imgui-raw-knobs
+version:        1.0.0
+synopsis:       Raw FFI bindings to imgui-knobs (altschuler/imgui-knobs) for dear-imgui-raw.
+description:    Generated with dear_bindings from the bundled imgui-knobs sources, compiled against the Dear ImGui build in dear-imgui-raw.
+category:       GUI
+maintainer:     IC Rainbow <aenor.realm@gmail.com>
+license:        BSD-3-Clause
+license-file:   LICENSE
+build-type:     Simple
+extra-doc-files:
+    README.md
+    CHANGELOG.md
+
+library
+  exposed-modules:
+      DearImGui.Raw.ImGuiKnobs
+      DearImGui.Raw.ImGuiKnobs.Enums.Flags
+      DearImGui.Raw.ImGuiKnobs.Enums.Variant
+  other-modules:
+      Paths_dear_imgui_raw_knobs
+  autogen-modules:
+      Paths_dear_imgui_raw_knobs
+  hs-source-dirs:
+      src
+  default-extensions:
+      BlockArguments
+      DataKinds
+      DuplicateRecordFields
+      LambdaCase
+      NoFieldSelectors
+      OverloadedRecordDot
+      OverloadedStrings
+      StrictData
+  ghc-options: -Wall -optc-Wno-discarded-qualifiers -optc-Wno-incompatible-pointer-types
+  cxx-options: -std=c++11 -fpermissive
+  include-dirs:
+      cbits
+      cbits/imgui-knobs
+  install-includes:
+      dcimgui_knobs.h
+      imgui-knobs/imgui-knobs.h
+      DearImGuiWrappers.h
+  cxx-sources:
+      cbits/dcimgui_knobs.cpp
+      cbits/imgui-knobs/imgui-knobs.cpp
+      cbits/DearImGuiWrappers.cpp
+  extra-libraries:
+      stdc++
+  build-tool-depends:
+      hsc2hs:hsc2hs
+  build-depends:
+      base >=4.16 && <5
+    , dear-imgui-raw ==1.0.*
+  default-language: GHC2021
diff --git a/src/DearImGui/Raw/ImGuiKnobs.hsc b/src/DearImGui/Raw/ImGuiKnobs.hsc
new file mode 100644
--- /dev/null
+++ b/src/DearImGui/Raw/ImGuiKnobs.hsc
@@ -0,0 +1,53 @@
+{-# LANGUAGE CApiFFI #-}
+{-# LANGUAGE PatternSynonyms #-}
+
+-- This file was generated by dear-bindings-ffi. Do not edit by hand.
+
+module DearImGui.Raw.ImGuiKnobs
+  ( knob
+  , knobInt
+  ) where
+
+import DearImGui.Raw.ImGuiKnobs.Enums.Flags (Flags)
+import DearImGui.Raw.ImGuiKnobs.Enums.Variant (Variant)
+import Foreign.C.String (CString)
+import Foreign.C.Types
+import Foreign.Ptr (Ptr)
+
+#include "dcimgui_knobs.h"
+
+-- functions
+
+-- C: bool ImGuiKnobs::Knob(const char* label, float* p_value, float v_min, float v_max, float speed, const char* format, ImGuiKnobVariant variant, float size, ImGuiKnobFlags flags, int steps, float angle_min, float angle_max)
+foreign import capi unsafe "dcimgui_knobs.h ImGuiKnobsKnob"
+  knob
+    :: CString -- ^ label
+    -> (Ptr Float) -- ^ p_value
+    -> Float -- ^ v_min
+    -> Float -- ^ v_max
+    -> Float -- ^ speed
+    -> CString -- ^ format
+    -> Variant -- ^ variant
+    -> Float -- ^ size
+    -> Flags -- ^ flags
+    -> CInt -- ^ steps
+    -> Float -- ^ angle_min
+    -> Float -- ^ angle_max
+    -> IO CBool
+
+-- C: bool ImGuiKnobs::KnobInt(const char* label, int* p_value, int v_min, int v_max, float speed, const char* format, ImGuiKnobVariant variant, float size, ImGuiKnobFlags flags, int steps, float angle_min, float angle_max)
+foreign import capi unsafe "dcimgui_knobs.h ImGuiKnobsKnobInt"
+  knobInt
+    :: CString -- ^ label
+    -> (Ptr CInt) -- ^ p_value
+    -> CInt -- ^ v_min
+    -> CInt -- ^ v_max
+    -> Float -- ^ speed
+    -> CString -- ^ format
+    -> Variant -- ^ variant
+    -> Float -- ^ size
+    -> Flags -- ^ flags
+    -> CInt -- ^ steps
+    -> Float -- ^ angle_min
+    -> Float -- ^ angle_max
+    -> IO CBool
diff --git a/src/DearImGui/Raw/ImGuiKnobs/Enums/Flags.hsc b/src/DearImGui/Raw/ImGuiKnobs/Enums/Flags.hsc
new file mode 100644
--- /dev/null
+++ b/src/DearImGui/Raw/ImGuiKnobs/Enums/Flags.hsc
@@ -0,0 +1,46 @@
+{-# LANGUAGE CApiFFI #-}
+{-# LANGUAGE PatternSynonyms #-}
+
+-- This file was generated by dear-bindings-ffi. Do not edit by hand.
+
+module DearImGui.Raw.ImGuiKnobs.Enums.Flags
+  ( Flags
+  , pattern AlwaysClamp
+  , pattern DragHorizontal
+  , pattern DragVertical
+  , pattern Logarithmic
+  , pattern NoInput
+  , pattern NoTitle
+  , pattern ValueTooltip
+  ) where
+
+import Foreign.C.Types
+
+#include "dcimgui_knobs.h"
+
+-- typedefs
+
+type Flags = CInt
+
+-- enums
+
+pattern NoTitle :: Flags
+pattern NoTitle = #{const ImGuiKnobFlags_NoTitle}
+
+pattern NoInput :: Flags
+pattern NoInput = #{const ImGuiKnobFlags_NoInput}
+
+pattern ValueTooltip :: Flags
+pattern ValueTooltip = #{const ImGuiKnobFlags_ValueTooltip}
+
+pattern DragHorizontal :: Flags
+pattern DragHorizontal = #{const ImGuiKnobFlags_DragHorizontal}
+
+pattern DragVertical :: Flags
+pattern DragVertical = #{const ImGuiKnobFlags_DragVertical}
+
+pattern Logarithmic :: Flags
+pattern Logarithmic = #{const ImGuiKnobFlags_Logarithmic}
+
+pattern AlwaysClamp :: Flags
+pattern AlwaysClamp = #{const ImGuiKnobFlags_AlwaysClamp}
diff --git a/src/DearImGui/Raw/ImGuiKnobs/Enums/Variant.hsc b/src/DearImGui/Raw/ImGuiKnobs/Enums/Variant.hsc
new file mode 100644
--- /dev/null
+++ b/src/DearImGui/Raw/ImGuiKnobs/Enums/Variant.hsc
@@ -0,0 +1,46 @@
+{-# LANGUAGE CApiFFI #-}
+{-# LANGUAGE PatternSynonyms #-}
+
+-- This file was generated by dear-bindings-ffi. Do not edit by hand.
+
+module DearImGui.Raw.ImGuiKnobs.Enums.Variant
+  ( Variant
+  , pattern Dot
+  , pattern Space
+  , pattern Stepped
+  , pattern Tick
+  , pattern Wiper
+  , pattern WiperDot
+  , pattern WiperOnly
+  ) where
+
+import Foreign.C.Types
+
+#include "dcimgui_knobs.h"
+
+-- typedefs
+
+type Variant = CInt
+
+-- enums
+
+pattern Tick :: Variant
+pattern Tick = #{const ImGuiKnobVariant_Tick}
+
+pattern Dot :: Variant
+pattern Dot = #{const ImGuiKnobVariant_Dot}
+
+pattern Wiper :: Variant
+pattern Wiper = #{const ImGuiKnobVariant_Wiper}
+
+pattern WiperOnly :: Variant
+pattern WiperOnly = #{const ImGuiKnobVariant_WiperOnly}
+
+pattern WiperDot :: Variant
+pattern WiperDot = #{const ImGuiKnobVariant_WiperDot}
+
+pattern Stepped :: Variant
+pattern Stepped = #{const ImGuiKnobVariant_Stepped}
+
+pattern Space :: Variant
+pattern Space = #{const ImGuiKnobVariant_Space}
