diff --git a/apps/docs/src/sections/ApiDocs.tsx b/apps/docs/src/sections/ApiDocs.tsx
index 32d5509..12d3dbb 100644
--- a/apps/docs/src/sections/ApiDocs.tsx
+++ b/apps/docs/src/sections/ApiDocs.tsx
@@ -52,6 +52,9 @@ export const ApiDocs: React.FC = () => (
+
+
+
@@ -95,6 +98,9 @@ export const ApiDocs: React.FC = () => (
+
+
+
diff --git a/apps/docs/src/sections/Gallery.tsx b/apps/docs/src/sections/Gallery.tsx
index 68977af..5782530 100644
--- a/apps/docs/src/sections/Gallery.tsx
+++ b/apps/docs/src/sections/Gallery.tsx
@@ -1,5 +1,6 @@
import React from 'react';
import {
+ AlphaDisplay,
Arc,
DreamknobProvider,
Fader,
@@ -13,14 +14,57 @@ import {
Meter,
NeonKnob,
Pointer,
+ PushButton,
RubberKnob,
SegmentDisplay,
SteppedKnob,
Ticks,
VintageKnob,
+ XYPad,
logTaper,
} from 'dreamknob';
+const PRESETS = [
+ { name: 'INIT PATCH', cutoff: 50 },
+ { name: 'WARM PAD', cutoff: 22 },
+ { name: 'ACID 303', cutoff: 84 },
+];
+
+const PresetDemo: React.FC = () => {
+ const [preset, setPreset] = React.useState(0);
+ return (
+
+
+
undefined}
+ readOnly
+ animateChanges={{ duration: 350 }}
+ color="#3df2ad"
+ label="Cutoff"
+ aria-label="Preset cutoff"
+ />
+
+
+
+ {PRESETS.map((p, i) => (
+
on && setPreset(i)}
+ color="#3df2ad"
+ size={34}
+ aria-label={`Preset ${p.name}`}
+ >
+ {String.fromCharCode(65 + i)}
+
+ ))}
+
+
+ );
+};
+
/** Draw a film-strip of a simple hardware knob at runtime (stand-in for a KnobMan PNG). */
const useGeneratedStrip = (frames = 31, fs = 120): string | null => {
const [src, setSrc] = React.useState(null);
@@ -340,6 +384,59 @@ export const Gallery: React.FC = () => (
/>
+
+
+
+
+
+ (v >= 1000 ? `${(v / 1000).toFixed(1)}k` : `${Math.round(v)}`)}
+ color="#e44cff"
+ label="Filter"
+ aria-label="Filter XY pad"
+ />
+
+
+
+
+
+
+
+ `${v} %`}
+ label="Blend"
+ aria-label="Bubble demo"
+ />
+
+
+
+
+
+
diff --git a/packages/dreamknob/README.md b/packages/dreamknob/README.md
index bc7c94b..febe38e 100644
--- a/packages/dreamknob/README.md
+++ b/packages/dreamknob/README.md
@@ -71,6 +71,11 @@ All knobs render `role="slider"` with `aria-valuemin/max/now/text`.
- `wheelStep` / `wheelRequiresFocus` — tune wheel notches, or keep hover-scroll free.
- `onChange` / `onChangeStart` / `onChangeEnd` — gesture-aware callbacks with
`meta.source` (`'drag' | 'wheel' | 'keyboard' | 'reset' | 'api'`).
+- `wrap` — endless encoder mode: values roll around min↔max (pair with
+ `angleOffset={0} angleRange={360}`).
+- `animateChanges` — tween the pointer on programmatic changes (preset loads);
+ gestures never animate and `prefers-reduced-motion` is honored.
+- `valueBubble` — floating readout above the control while dragging.
- `name` — hidden form input for plain `