Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
414 commits
Select commit Hold shift + click to select a range
ee86516
browser: the status bar's clock says 04:47 on Safari and Chrome, not …
mertbuilds Oct 4, 2026
40edf70
browser: the battery is charged to 69 on Safari and Chrome, iOS writi…
mertbuilds Oct 4, 2026
d3a803b
keys: / from inside the frame focuses the panel's search while the pa…
mertbuilds Oct 4, 2026
ae7ce0c
panel: the mock and touch pointer switches hide through their offers,…
mertbuilds Oct 4, 2026
3c5224a
touch pointer: a press on a slider, editable text, a scrollbar or ano…
mertbuilds Oct 4, 2026
49c019d
build: the bezel addresses are written from assets/bezels before each…
mertbuilds Oct 4, 2026
8519aca
docs: a tap's mouse events come after touchend, a press on a slider, …
mertbuilds Oct 4, 2026
40b22c4
frame: a knob changed while the frame's page is on its way to a slow …
mertbuilds Oct 4, 2026
7706bb4
frame: a page that comes back to this origin from another one, where …
mertbuilds Oct 4, 2026
3d760e8
test: the claim's fakes let go as unmount does, nothing once taken ov…
mertbuilds Oct 4, 2026
4b547e5
frame: width.ts keeps the frame and leaves the rest to their own modu…
mertbuilds Oct 4, 2026
eee8f81
engine: one svgNode, browserkit's, for the mock, the mat and the bars…
mertbuilds Oct 4, 2026
d2b4db0
engine: the mock's unused bezel field gone, its tests reading the ins…
mertbuilds Oct 4, 2026
dc469e7
touch pointer: the click after a press on a slider or editable text k…
mertbuilds Oct 4, 2026
19f5881
Merge pull request #11 from mertbuilds/feat/grab
mertbuilds Oct 4, 2026
0d37010
Merge pull request #10 from mertbuilds/feat/devices-ua-pins
mertbuilds Oct 4, 2026
3b54013
Merge pull request #9 from mertbuilds/feat/panel-revamp
mertbuilds Oct 4, 2026
163d607
Merge pull request #8 from mertbuilds/feat/time-travel
mertbuilds Oct 4, 2026
f5321be
Merge pull request #7 from mertbuilds/feat/geo-timezone-native
mertbuilds Oct 4, 2026
5b21c60
Merge pull request #6 from mertbuilds/feat/locale-text-native
mertbuilds Oct 4, 2026
1d5f313
Merge pull request #5 from mertbuilds/feat/motion-early-readers
mertbuilds Oct 4, 2026
cd94ef5
Merge pull request #4 from mertbuilds/feat/frame-native-layer
mertbuilds Oct 4, 2026
558a07b
Merge pull request #3 from mertbuilds/feat/width-iframe-viewport
mertbuilds Oct 4, 2026
3e8c2c2
0.0.3
mertbuilds Oct 4, 2026
2383cd2
ui: the handle's corner stays square while a closing panel still shows
mertbuilds Oct 5, 2026
4729373
ui: the panel lives on either side, drags or flings across, and keeps…
mertbuilds Oct 5, 2026
336a0c7
ui: opening the panel puts the focus in the search
mertbuilds Oct 5, 2026
7ca97e3
ui: the panel's default hotkey is k
mertbuilds Oct 5, 2026
17f9f93
ui: focus, touch and kept-place fixes from review
mertbuilds Oct 5, 2026
3b732f1
ui: shift k opens the panel, shift r replays, shift g grabs
mertbuilds Oct 5, 2026
6d65749
grab: shift g turns it on and off on a press, and keys go by the lett…
mertbuilds Oct 5, 2026
5dcd99f
ui: a fresh panel lists device, scheme, grab, text size and locale
mertbuilds Oct 5, 2026
1c79d03
keys: a plain scroll box with the focus leaves the shortcuts on
mertbuilds Oct 5, 2026
25f459b
grab: turning on takes the focus out of the panel, so the arrows are …
mertbuilds Oct 5, 2026
0deb70e
ui: a panel dragged off its edge rounds the side that sat on it
mertbuilds Oct 6, 2026
a6025fa
grab: the frame glides on transforms alone, with no layout or page pa…
mertbuilds Oct 6, 2026
e4ce04b
grab frame holds at fractional pixel ratios, and a docked panel draws…
mertbuilds Oct 6, 2026
d3aed8e
ui: a fling goes by the fastest stretch of the drag, and a long glide…
mertbuilds Oct 6, 2026
f036ba7
grab: the frame waits for the pointer to settle before it moves on
mertbuilds Oct 6, 2026
002a628
ui: grab is an action, not a row
mertbuilds Oct 6, 2026
cf0bd3b
ui: rows regrouped, device and viewport split, related knobs merged
mertbuilds Oct 6, 2026
888fad0
ui: add knob button under the rows, search at the bottom, rows reorde…
mertbuilds Oct 6, 2026
b52d674
ui: row icons from lucide
mertbuilds Oct 6, 2026
c331dd8
ui: the reorder grip gets its own column, centred on the row
mertbuilds Oct 6, 2026
a0a6f61
ui: a centred half sun, half moon scheme icon, and a tighter grip
mertbuilds Oct 6, 2026
c7cc123
mat: color knob with classic green, magenta and more
mertbuilds Oct 6, 2026
378d2ba
ui: rows open in place, search sits over its results, panel 20% taller
mertbuilds Oct 6, 2026
298ee58
frame: device changes animate, and a reload keeps the mat, case and s…
mertbuilds Oct 6, 2026
7abf56b
Merge branch 'feat/mat-colors' into feat/panel-sides
mertbuilds Oct 6, 2026
f3ae2eb
mat: the reload cover and snapshot follow the chosen mat color
mertbuilds Oct 6, 2026
83376f8
ui: reordering rows keeps the focus, the device row's x leaves a set …
mertbuilds Oct 6, 2026
0024140
frame: the reload button waits for the new page, its stop glyph stops…
mertbuilds Oct 6, 2026
06bc651
keys: shortcuts can be rebound from the panel and are kept per site
mertbuilds Oct 6, 2026
9d65a9e
frame: the mat's opening is drawn each frame, not left to an off-thre…
mertbuilds Oct 6, 2026
8dd2e1a
safari: reload and stop glyphs redrawn to match iOS 26 safari
mertbuilds Oct 6, 2026
15506cd
ui: tooltips, a refused key shakes and says why, a knob picked by nam…
mertbuilds Oct 6, 2026
4128c77
frame: rounded per-device opening that tracks the screen, and rotatio…
mertbuilds Oct 6, 2026
d4714ae
keys: acted-on keys skip the browser default, recording turns grab of…
mertbuilds Oct 6, 2026
8463f41
device: one iPhone Duo with a fold posture, folding in 3D around its …
mertbuilds Oct 6, 2026
b7deb58
fold: the page blurs through the fold and the turn, the swinging half…
mertbuilds Oct 6, 2026
e14ee87
fold: apple's hinge spring, light and blur follow the hinge, page pic…
mertbuilds Oct 6, 2026
5e7f112
fold: apple's wipe model with flat-window wedges, plus review fixes: …
mertbuilds Oct 7, 2026
e860851
fold: every layer takes its screen's rounded corners, true arcs for t…
mertbuilds Oct 7, 2026
c63f5ee
fold: the duo turns through frames rendered from Apple's model, the p…
mertbuilds Oct 7, 2026
9804ee1
fold: frames packed at 1.5x as hollow pieces, decoded at fold start a…
mertbuilds Oct 7, 2026
7eb2ba7
fold: no black past the case, frames warped to meet between steps, fo…
mertbuilds Oct 7, 2026
6f9b73b
ui: settings view behind a gear, the handle can be hidden
mertbuilds Oct 7, 2026
5f8f820
fold: the page stays flat behind the turning screen, black where the …
mertbuilds Oct 7, 2026
9c7b070
fold: the page's top and bottom edges blur into the black, as the scr…
mertbuilds Oct 7, 2026
023dd5a
ui: settings slide in like ios navigation, with a back button
mertbuilds Oct 7, 2026
7ae17fb
ui: a hidden handle never takes the focus back; fold frames are about…
mertbuilds Oct 7, 2026
7cf23ee
fold: cover corners measured rigid, a black backing under the case, f…
mertbuilds Oct 7, 2026
aed04d8
device: an experimental fold slider scrubs the duo's hinge with apple…
mertbuilds Oct 7, 2026
35d74ef
device: the fold chip is back beside the slider, and the thumb follow…
mertbuilds Oct 7, 2026
7d73528
ui: settings push the rows fully out, one movement both ways
mertbuilds Oct 7, 2026
feaa412
ui: settings labels line up with the rows' titles
mertbuilds Oct 7, 2026
247d619
mat: a new mat colour splashes out from behind the device in a random…
mertbuilds Oct 7, 2026
9295156
mat: the splash spreads over 1.2s on a gentler curve
mertbuilds Oct 7, 2026
4501919
fold: the moving screen is drawn by a small WebGL2 pass, soft ends bl…
mertbuilds Oct 7, 2026
1c8313a
ui: settings items are built as knob rows, grip space kept empty
mertbuilds Oct 7, 2026
bd6c6f8
fold: exact frames every 2° with no warp, both halves from one render…
mertbuilds Oct 7, 2026
981a10a
readme: how the iphone duo folds, with thanks to jadon7
mertbuilds Oct 7, 2026
2ad87fb
fold: frames re-rendered with Apple's dark screen border and flat end…
mertbuilds Oct 7, 2026
149711e
fold: safari's bars blur with the page, and the free edge fades into …
mertbuilds Oct 7, 2026
fe4e420
ui: the user agent box shows only for a custom user agent
mertbuilds Oct 7, 2026
5dd6385
ui: clock, header, zoom and mat controls show only when they do somet…
mertbuilds Oct 7, 2026
e0328be
fold: every degree, dark metal shaded from Apple's pictures, the hing…
mertbuilds Oct 7, 2026
25d3490
ui: settings rows get icons and end on the rows' right edge; the curr…
mertbuilds Oct 7, 2026
38c9e97
release: drop the temporary slow-motion aid
mertbuilds Oct 7, 2026
5c0c1a9
store: version every stored item
mertbuilds Oct 7, 2026
8096b67
fold: well-formed svg data urls, the fold slider lets go on destroy, …
mertbuilds Oct 7, 2026
ab32ef7
0.1.0
mertbuilds Oct 7, 2026
e4869c6
Merge pull request #12 from mertbuilds/feat/panel-sides
mertbuilds Oct 7, 2026
56c7bdb
fold: every layer follows the frame on screen, nothing moves between …
mertbuilds Oct 8, 2026
8613f6d
ui: panel.ts and catalog.ts split into focused modules, no behaviour …
mertbuilds Oct 8, 2026
a82c694
Merge branch 'refactor/split-panel' into fix/fold-layer-lock
mertbuilds Oct 8, 2026
1192786
fold: the turning screen's free edge darkens as it stands up, measure…
mertbuilds Oct 8, 2026
457c102
fold: the whole turning screen blurs near a right angle, mapped from …
mertbuilds Oct 8, 2026
78d6269
ui: the status bar clock reads 04:20
mertbuilds Oct 8, 2026
4ce34d1
fold: light() takes every argument, and the fallback edge and masks a…
mertbuilds Oct 8, 2026
9865f2f
0.1.1
mertbuilds Oct 8, 2026
a97d279
Merge pull request #13 from mertbuilds/fix/fold-layer-lock
mertbuilds Oct 8, 2026
1f8de4b
ui: a shrinking panel keeps its top
mertbuilds Oct 8, 2026
97498a4
frame: the device glides over when the panel changes side
mertbuilds Oct 8, 2026
8e3eb66
changelog: 0.1.1 panel and frame fixes
mertbuilds Oct 8, 2026
0fbdb4e
Merge pull request #14 from mertbuilds/fix/panel-anchor-and-side-move
mertbuilds Oct 8, 2026
c899eec
fold: a fold the knobs start is warm from its first frame
mertbuilds Oct 9, 2026
38317b3
fold: the picture of the page is drawn in the page's own fonts
mertbuilds Oct 9, 2026
c25cb1e
build: "use client" once, on the first line, and a way to try a local…
mertbuilds Oct 9, 2026
cf82d47
fold: a fold no hand holds goes at one speed, with no easing
mertbuilds Oct 9, 2026
9594dab
fold, link: nothing is kept after a failure
mertbuilds Oct 9, 2026
9e755c1
0.1.2
mertbuilds Oct 9, 2026
b5dbbfa
Merge pull request #15 from mertbuilds/fix/fold-click-warm
mertbuilds Oct 9, 2026
dcb38df
touch pointer: the cursor sits in the top layer, over dialogs and pop…
mertbuilds Oct 10, 2026
74e8400
touch pointer: the cursor goes over a dialog in a shadow root too
mertbuilds Oct 10, 2026
b176874
touch pointer: a move puts the cursor back over a dialog in a shadow …
mertbuilds Oct 10, 2026
f544583
fresh mode: ?devknobs=fresh keeps nothing, so each visit is a first one
mertbuilds Oct 10, 2026
98caf27
fresh mode: a store out of reach stays owned, and only a real load is…
mertbuilds Oct 10, 2026
b8e9138
panel: a fresh panel starts 128 down the edge, not at the very top
mertbuilds Oct 10, 2026
27644f9
panel: tests pin the start height and the edge of an older place
mertbuilds Oct 10, 2026
ed996e1
fresh mode: the switch stays in the address, and another tab changes …
mertbuilds Oct 10, 2026
80919e4
Merge branch 'feat/fresh-mode' into feat/panel-start-place
mertbuilds Oct 10, 2026
0b2f523
pane: a side pane docked beside the panel, for views that need the width
mertbuilds Oct 10, 2026
dc10617
Merge branch 'feat/panel-start-place' into feat/side-pane
mertbuilds Oct 10, 2026
f3de413
touch pointer: one cursor for the whole screen, over the browser's ba…
mertbuilds Oct 10, 2026
9807243
Merge branch 'fix/touch-pointer-top-layer' into feat/fresh-mode
mertbuilds Oct 10, 2026
082b192
Merge branch 'feat/fresh-mode' into feat/panel-start-place
mertbuilds Oct 10, 2026
c36cda9
touch pointer: the cursor leaves with its page, and tests hold its pl…
mertbuilds Oct 10, 2026
e98cf9f
Merge branch 'fix/touch-pointer-top-layer' into feat/fresh-mode
mertbuilds Oct 10, 2026
f11b508
Merge branch 'feat/fresh-mode' into feat/panel-start-place
mertbuilds Oct 10, 2026
6ee3993
requests: a log of what the page asks for, kept from its first request
mertbuilds Oct 10, 2026
735c3fc
styles: the rules an element takes, in the order the cascade settles …
mertbuilds Oct 10, 2026
d57bddc
requests: the log in the side pane, with a request's detail and a cop…
mertbuilds Oct 10, 2026
69b3091
Merge branch 'feat/panel-start-place' into feat/side-pane
mertbuilds Oct 10, 2026
76d3359
Merge branch 'feat/side-pane' into feat/requests-pane
mertbuilds Oct 10, 2026
cdcff3b
requests: the newest request shows on top
mertbuilds Oct 10, 2026
967fd49
inspect: pick an element and read its styles in the side pane
mertbuilds Oct 10, 2026
833626d
requests: no mark on frame rows, and the page's streams and keys are …
mertbuilds Oct 10, 2026
f7fbf0d
panel: pin it to the side as a full-height column, and the page takes…
mertbuilds Oct 10, 2026
247dc46
requests: marks and colors for kinds, methods and statuses
mertbuilds Oct 10, 2026
ca0107b
pane: a view shows inside the one panel, which grows for it and takes…
mertbuilds Oct 10, 2026
64e552f
Merge branch 'feat/side-pane' into feat/requests-pane
mertbuilds Oct 10, 2026
a7f2e74
Merge branch 'feat/side-pane' into feat/css-pane
mertbuilds Oct 10, 2026
6bd13d2
inspect: the styles show in the panel's view at any width, and leave …
mertbuilds Oct 10, 2026
1104cbd
Merge branch 'feat/side-pane' into feat/pin-panel
mertbuilds Oct 10, 2026
c843f47
inspect: a simple mode lists what applies, and advanced keeps the rules
mertbuilds Oct 10, 2026
8ad116b
panel: actions are rows like any knob, and every head and view is bui…
mertbuilds Oct 10, 2026
43f97e5
Merge branch 'feat/side-pane' into feat/pin-panel
mertbuilds Oct 10, 2026
5e79441
Merge branch 'feat/side-pane' into feat/css-pane
mertbuilds Oct 10, 2026
5f5a91a
Merge branch 'feat/side-pane' into feat/requests-pane
mertbuilds Oct 10, 2026
6fb89d9
Merge branch 'feat/css-pane' into try/all
mertbuilds Oct 10, 2026
85f383d
Merge branch 'feat/pin-panel' into try/all
mertbuilds Oct 10, 2026
8f8536a
panel: the page's frame follows the pinned column as it slides and grows
mertbuilds Oct 10, 2026
1733bee
Merge branch 'feat/pin-panel' into try/all
mertbuilds Oct 10, 2026
14fce45
fold: the page's picture keeps the root text size, the hinge side sta…
mertbuilds Oct 10, 2026
a1defdc
Merge branch 'fix/fold-text-size-blur' into try/all
mertbuilds Oct 10, 2026
a03f578
Merge branch 'fix/fold-text-size-blur' into try/all
mertbuilds Oct 10, 2026
e0a35c1
fold: the blurred layers hand over to each other with no line, and th…
mertbuilds Oct 10, 2026
fe04c78
Merge branch 'fix/fold-text-size-blur' into try/all
mertbuilds Oct 10, 2026
8297428
fold: no shade over the half that turns, and one that is asked for be…
mertbuilds Oct 10, 2026
e107f41
requests: a request opens on its path and its bodies, with headers an…
mertbuilds Oct 10, 2026
bcbae08
Merge branch 'feat/requests-pane' into try/all
mertbuilds Oct 10, 2026
09b8da7
inspect: the box model on the page and in the panel, and a card of wh…
mertbuilds Oct 10, 2026
397b596
Merge branch 'feat/css-pane' into try/all
mertbuilds Oct 10, 2026
33938fd
Merge branch 'fix/fold-text-size-blur' into try/all
mertbuilds Oct 10, 2026
cc40e12
fold: the tuning hook gives the page's picture, the angle and jadon7'…
mertbuilds Oct 10, 2026
8a98345
storage: what the page keeps in the browser, with a way to clear it a…
mertbuilds Oct 10, 2026
bae02a6
Merge branch 'feat/storage-view' into try/all
mertbuilds Oct 10, 2026
7aaedb6
fold: the page's picture draws its images as the page fits them, at t…
mertbuilds Oct 11, 2026
1186ee0
Merge branch 'fix/fold-text-size-blur' into try/all
mertbuilds Oct 11, 2026
15fe26a
fold: one way through the shader for every pixel, so no line shows wh…
mertbuilds Oct 11, 2026
91a11f7
Merge branch 'fix/fold-text-size-blur' into try/all
mertbuilds Oct 11, 2026
b4237c5
fold: blur never darkens, and the hinge side of the turning half has …
mertbuilds Oct 11, 2026
7ec09da
Merge branch 'fix/fold-text-size-blur' into try/all
mertbuilds Oct 11, 2026
7ce960b
fold: no line and no shade at the hinge, and the blur at the top and …
mertbuilds Oct 11, 2026
634f44c
Merge branch 'fix/fold-text-size-blur' into try/all
mertbuilds Oct 11, 2026
c32a35d
fold: the turning half is drawn as it was, and its clip ends short of…
mertbuilds Oct 11, 2026
3edbe0c
Merge branch 'fix/fold-text-size-blur' into try/all
mertbuilds Oct 11, 2026
28e60f2
Merge branch 'fix/fold-text-size-blur' into try/all
mertbuilds Oct 11, 2026
bddebf0
fold: the black under the turning half ends short of its clip, so non…
mertbuilds Oct 11, 2026
d369215
Merge branch 'fix/fold-text-size-blur' into try/all
mertbuilds Oct 11, 2026
d3f8aa3
build: the fold tuning table is left out of the package and stays on …
mertbuilds Oct 11, 2026
2eed746
frame: an outside page can be shown in the device, with the knobs tha…
mertbuilds Oct 11, 2026
c204dc7
Merge branch 'feat/outside-page' into try/all
mertbuilds Oct 11, 2026
adcef2c
frame: the touch cursor is left off over an outside page
mertbuilds Oct 11, 2026
eb4de88
frame: the device's own screen follows the scheme around an outside page
mertbuilds Oct 11, 2026
2e5f229
scroll: a reload a knob causes comes back to the same place, in the p…
mertbuilds Oct 11, 2026
09e5871
frame: the back button leaves an outside page for the own one
mertbuilds Oct 11, 2026
4cb1bf1
Merge branch 'feat/outside-page' into try/all
mertbuilds Oct 11, 2026
238933c
Merge branch 'fix/reload-keeps-scroll' into try/all
mertbuilds Oct 11, 2026
aff1514
scroll: the kept place goes through fresh mode's storage, and an outs…
mertbuilds Oct 11, 2026
77793fd
Merge branch 'feat/outside-page' into feat/outside-fold
mertbuilds Oct 11, 2026
8080a8d
frame: the host can give an outside page's colours for the device's o…
mertbuilds Oct 11, 2026
347bb34
Merge branch 'feat/outside-page' into tmp/merge-look
mertbuilds Oct 11, 2026
5e39156
fold: a live copy of an outside page folds where a picture of the pag…
mertbuilds Oct 11, 2026
59f3aae
fold: an outside page on the Duo keeps a live copy for each screen, l…
mertbuilds Oct 11, 2026
6631638
docs: the Duo folds an outside page, and what that costs
mertbuilds Oct 11, 2026
8804e1d
fold: the dark at a live copy's two ends starts at the screen's side
mertbuilds Oct 11, 2026
ff12e51
Merge branch 'feat/outside-fold' into tmp/merge-fold
mertbuilds Oct 11, 2026
f26b1d1
fold: an outside page's copies stay out of the log of requests
mertbuilds Oct 11, 2026
6e81c72
inspect: picking is a mode that ends with the pick, with a select but…
mertbuilds Oct 12, 2026
66a2fe5
Merge branch 'feat/css-pane' into tmp/merge-pick
mertbuilds Oct 12, 2026
e691747
inspect: its row's x and reset all let go of the element it holds, an…
mertbuilds Oct 12, 2026
8cf6961
mat, grab: any color paints the mat and grab, its lines light or dark…
mertbuilds Oct 12, 2026
d9255bc
ui: one refusal for a value a control cannot take, the shortcuts' own
mertbuilds Oct 12, 2026
857ed8f
ui: the mat and grab take colors of your own, from a plus after the s…
mertbuilds Oct 12, 2026
91a28e3
ui: a color's x stands after its swatch, so each swatch is the radio …
mertbuilds Oct 12, 2026
e9d0f4e
Merge branch 'feat/custom-colors' into tmp/merge-colors
mertbuilds Oct 12, 2026
38e32d3
colors: fresh mode keeps none, and the swatch list is built from the …
mertbuilds Oct 12, 2026
aed1fc9
Revert "fold: an outside page's copies stay out of the log of requests"
mertbuilds Oct 12, 2026
8c5b351
Revert "Merge branch 'feat/outside-fold' into tmp/merge-fold"
mertbuilds Oct 12, 2026
bfa448a
Revert "Merge branch 'feat/outside-page' into tmp/merge-look"
mertbuilds Oct 12, 2026
37cfe1f
Revert "scroll: the kept place goes through fresh mode's storage, and…
mertbuilds Oct 12, 2026
814c609
Revert "Merge branch 'feat/outside-page' into try/all"
mertbuilds Oct 12, 2026
f3bb0b6
Revert "frame: the touch cursor is left off over an outside page"
mertbuilds Oct 12, 2026
1908a32
Revert "Merge branch 'feat/outside-page' into try/all"
mertbuilds Oct 12, 2026
4c2d12b
scroll: the kept place goes through fresh mode's storage again, and i…
mertbuilds Oct 12, 2026
208d237
settings: its head and rows are the views' own, on the knob rows' col…
mertbuilds Oct 12, 2026
026687c
Merge branch 'feat/side-pane' into tmp/merge-settings
mertbuilds Oct 12, 2026
2db3931
pin: a pinned panel closes first and its handle comes in after, so no…
mertbuilds Oct 12, 2026
8958a6d
Merge branch 'feat/pin-panel' into tmp/merge-handle
mertbuilds Oct 12, 2026
80821ca
ui: every line stands on one set of columns, and a view's layout says…
mertbuilds Oct 12, 2026
0264894
ui: tests read where each line starts off the stylesheet, and no rule…
mertbuilds Oct 12, 2026
d71936e
Merge branch 'try/all' into fix/view-columns
mertbuilds Oct 12, 2026
d7e09fc
inspect: its select button stands first on the view's own line
mertbuilds Oct 12, 2026
90b4601
inspect: with no element there is no bar, and the empty line starts t…
mertbuilds Oct 12, 2026
59038aa
storage: the kit has a table's line, its name and value on columns ev…
mertbuilds Oct 12, 2026
0a5c73c
storage: a list of the stores by their full names, each opening a pag…
mertbuilds Oct 12, 2026
1be47bc
Merge branch 'try/all' into feat/storage-layout
mertbuilds Oct 12, 2026
d017843
inspect: a value's var() are found as css reads it, past strings, com…
mertbuilds Oct 12, 2026
074f49a
ui: a tooltip can show a node handed to it, for more than one line of…
mertbuilds Oct 12, 2026
f6613b2
inspect: every var() says what the element sees for it on hover and f…
mertbuilds Oct 12, 2026
987e57e
Merge branch 'try/all' into feat/inspect-var-values
mertbuilds Oct 12, 2026
f8766c7
storage: the icon set has lucide's table-2, cookie, hard-drive and bo…
mertbuilds Oct 12, 2026
b8e864b
pane: a view under another slides in over it and pops back, under the…
mertbuilds Oct 12, 2026
b6f9a3d
storage: the kit has a table's head on its lines' columns, a line's n…
mertbuilds Oct 12, 2026
44592d1
storage: the stores are a tree, flush with the head, whose nodes open…
mertbuilds Oct 12, 2026
da0795f
Merge branch 'try/all' into feat/storage-layout
mertbuilds Oct 12, 2026
0da4d0c
Revert "pane: a view under another slides in over it and pops back, u…
mertbuilds Oct 12, 2026
34813be
storage: a fold's own icon stands after its chevron, a very tall fold…
mertbuilds Oct 12, 2026
16d4d93
storage: one tree and no pages: every store folds out in place to its…
mertbuilds Oct 12, 2026
1db91db
0.2.0
mertbuilds Oct 15, 2026
47305e3
Merge pull request #21 from mertbuilds/release/0.2.0
mertbuilds Oct 15, 2026
363faa2
chore: move devknobs into packages/devknobs with its history
mertbuilds Oct 15, 2026
0d6dab7
build: devknobs as a workspace package
mertbuilds Oct 15, 2026
4511d67
build: keep root oxlint and oxfmt off packages/devknobs
mertbuilds Oct 15, 2026
3e0b5f3
ci: build and test devknobs
mertbuilds Oct 15, 2026
e2c44fa
docs: monorepo layout and devknobs release
mertbuilds Oct 15, 2026
8a4082c
fix: links point to mertbuilds/knobs
mertbuilds Oct 15, 2026
c845872
build: pre-commit lint and format skip packages/devknobs
mertbuilds Oct 15, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
8 changes: 8 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,11 @@ jobs:
with:
node-version-file: .nvmrc
cache: pnpm
- uses: oven-sh/setup-bun@v2
with:
bun-version: 1.3.14
- run: pnpm install --frozen-lockfile
# Includes devknobs' build and typecheck (bun, tsc).
- run: pnpm exec turbo run lint typecheck build
- run: pnpm format:check
- run: pnpm skills:check
Expand All @@ -35,7 +39,11 @@ jobs:
with:
node-version-file: .nvmrc
cache: pnpm
- uses: oven-sh/setup-bun@v2
with:
bun-version: 1.3.14
- run: pnpm install --frozen-lockfile
# Storybook story tests run in real Chromium (vitest browser mode).
- run: pnpm --filter @knobs/ui exec playwright install chromium --with-deps
# Storybook stories and devknobs' bun tests.
- run: pnpm test
5 changes: 5 additions & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,12 @@ jobs:
with:
node-version-file: .nvmrc
cache: pnpm
- uses: oven-sh/setup-bun@v2
with:
bun-version: 1.3.14
- run: pnpm install --frozen-lockfile
# The site bundles devknobs from its dist.
- run: pnpm --filter devknobs build
- name: Build and deploy to Cloudflare Workers
uses: cloudflare/wrangler-action@v3
env:
Expand Down
5 changes: 5 additions & 0 deletions .github/workflows/preview.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,12 @@ jobs:
with:
node-version-file: .nvmrc
cache: pnpm
- uses: oven-sh/setup-bun@v2
with:
bun-version: 1.3.14
- run: pnpm install --frozen-lockfile
# The site bundles devknobs from its dist.
- run: pnpm --filter devknobs build
# No VITE_OPENPANEL_CLIENT_ID: preview traffic stays out of the analytics.
- run: pnpm --filter @knobs/web build
- name: Upload preview version
Expand Down
42 changes: 26 additions & 16 deletions AGENTS.md

Large diffs are not rendered by default.

29 changes: 24 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
# knobs

The marketing site for the `devknobs` npm package. <https://knobs.dev>
The `devknobs` npm package and its site, <https://knobs.dev>, in one monorepo:

A copy of [mertbuilds/web-starter](https://github.com/mertbuilds/web-starter) with everything a
| Path | What |
| -------------------- | ------------------------------------------------------------------ |
| `packages/devknobs/` | The `devknobs` npm package ([README](packages/devknobs/README.md)) |
| `apps/web/` | The site, knobs.dev |
| `packages/ui/` | The site's StyleX components |

The site is a copy of [mertbuilds/web-starter](https://github.com/mertbuilds/web-starter) with everything a
landing page does not need taken out: no api, no database, no auth, no billing, no e2e. What is
left is a TanStack Start app on Cloudflare Workers, the StyleX component package behind it, and
the tooling that keeps both honest. The founding stack decisions are in
Expand All @@ -24,7 +30,7 @@ this repo keeps only the web half. Agent rules and workflow live in [AGENTS.md](

## Develop

Prereqs: Node 24 (`nvm use`), pnpm 11 (corepack).
Prereqs: Node 24 (`nvm use`), pnpm 11 (corepack), bun 1.3 (devknobs builds and tests with it).

```sh
pnpm install
Expand All @@ -45,11 +51,11 @@ Local URLs come from [portless](https://portless.sh): stable named HTTPS domains
| Command | What it does |
| ------------------- | ------------------------------------------------------------------ |
| `pnpm dev` | Web + storybook, in mprocs panes |
| `pnpm test` | Storybook story tests in real Chromium |
| `pnpm test` | Story tests in real Chromium + devknobs' `bun test` |
| `pnpm lint` | oxlint, type-aware |
| `pnpm format:check` | oxfmt, the CI check |
| `pnpm typecheck` | `tsc --noEmit` per package |
| `pnpm build` | turbo build (the Workers bundle for `apps/web`) |
| `pnpm build` | turbo build (devknobs' `dist`, then the Workers bundle) |
| `pnpm storybook` | Component workshop (standalone, :6006) |
| `pnpm bad-day` | Nuke node_modules + all caches, reinstall (`DRY_RUN=1` to preview) |
| `pnpm skills:check` | Warn when dep majors drift from verified agent skills |
Expand All @@ -61,6 +67,19 @@ Local URLs come from [portless](https://portless.sh): stable named HTTPS domains
**Deploy.** `pnpm --filter @knobs/web deploy` builds and ships to Cloudflare Workers; a push to
main does the same from CI.

## devknobs

`pnpm dev` runs the site against devknobs' source, so an edit in `packages/devknobs/src` reloads
the page. To release a new version: bump `version` in `packages/devknobs/package.json`, add the
`CHANGELOG.md` entry, then:

```sh
pnpm --filter devknobs build
cd packages/devknobs
npm pack --dry-run # check the file list
npm publish
```

## Going to production: accounts checklist

- [ ] **Cloudflare**: Workers; secrets `CLOUDFLARE_API_TOKEN`, `CLOUDFLARE_ACCOUNT_ID` in GitHub
Expand Down
2 changes: 1 addition & 1 deletion apps/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
"@types/react": "^19.2.18",
"@types/react-dom": "^19.2.5",
"@vitejs/plugin-react": "^6.1.1",
"devknobs": "0.2.0",
"devknobs": "workspace:*",
"oxc-transform-react": "^0.148.0",
"typescript": "^7.0.2",
"vite": "^8.2.2",
Expand Down
7 changes: 4 additions & 3 deletions apps/web/src/routes/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,8 @@ const PANEL = '[data-devknobs="panel"]';

const DUO_CREDIT = 'https://github.com/jadon7/iphone-duo';

const NOTICES = 'https://github.com/mertbuilds/devknobs/blob/main/THIRD_PARTY_NOTICES.md';
const NOTICES =
'https://github.com/mertbuilds/knobs/blob/main/packages/devknobs/THIRD_PARTY_NOTICES.md';

const styles = create({
// The feature grid's own gap, so the line below it reads as a new block.
Expand Down Expand Up @@ -664,7 +665,7 @@ function Landing() {
<p {...props(styles.text, styles.afterFeatures)}>{m.features_panel()}</p>
<Hints />
<a
href="https://github.com/mertbuilds/devknobs#knobs"
href="https://github.com/mertbuilds/knobs/tree/main/packages/devknobs#knobs"
{...props(styles.link, styles.self, styles.withIcon)}
>
{m.features_readme()}
Expand Down Expand Up @@ -729,7 +730,7 @@ function Landing() {
</section>

<footer {...props(styles.footer)}>
<a href="https://github.com/mertbuilds/devknobs" {...props(styles.link, styles.withIcon)}>
<a href="https://github.com/mertbuilds/knobs" {...props(styles.link, styles.withIcon)}>
<GitHubMark />
{m.link_github()}
</a>
Expand Down
54 changes: 17 additions & 37 deletions apps/web/vite.config.ts
Original file line number Diff line number Diff line change
@@ -1,48 +1,27 @@
import { existsSync, realpathSync } from 'node:fs';
import { resolve } from 'node:path';
import { cloudflare } from '@cloudflare/vite-plugin';
import { paraglideVitePlugin } from '@inlang/paraglide-js';
import { unplugin as stylex } from '@stylexjs/unplugin';
import { tanstackStart } from '@tanstack/react-start/plugin/vite';
import react from '@vitejs/plugin-react';
import { build, defineConfig, type Plugin, searchForWorkspaceRoot } from 'vite';
import web from './package.json' with { type: 'json' };
import { build, defineConfig, type Plugin } from 'vite';
import { tuneEndpoint } from './vite.tune.ts';

const repoRoot = resolve(import.meta.dirname, '../..');

// The dev server runs devknobs from its local checkout, so the site tests the
// version in the works: DEVKNOBS_PATH (absolute, or relative to the repo root),
// else `devknobs` beside this checkout, which also holds for `knobs.dev.<branch>`
// worktrees. Builds keep the pinned npm package. The early script
// (`devknobs/early?raw`) is built from the checkout's current source too.
function localDevknobs(): Plugin {
const wanted = resolve(repoRoot, process.env.DEVKNOBS_PATH ?? '../devknobs');
const root = existsSync(resolve(wanted, 'src/index.ts')) ? realpathSync(wanted) : null;
// The dev server runs devknobs from its source in packages/devknobs, so an edit
// there reloads the page with no build. Builds use the package's dist, which
// turbo builds first. The early script (`devknobs/early?raw`) is built from the
// current source too.
function devknobsSource(): Plugin {
const root = resolve(import.meta.dirname, '../../packages/devknobs');
const early = '\0devknobs-early';
return {
apply: (_config, { command, isPreview }) => command === 'serve' && !isPreview,
config() {
if (!root) {
return;
}
return {
resolve: { alias: [{ find: /^devknobs$/, replacement: resolve(root, 'src/index.ts') }] },
server: { fs: { allow: [searchForWorkspaceRoot(process.cwd()), root] } },
};
},
configResolved({ logger }) {
if (root) {
logger.info(`devknobs: local ${root}`);
return;
}
logger.info(`devknobs: npm ${web.devDependencies.devknobs} (no local checkout at ${wanted})`);
},
config: () => ({
resolve: { alias: [{ find: /^devknobs$/, replacement: resolve(root, 'src/index.ts') }] },
}),
configureServer(server) {
if (!root) {
return;
}
// The source asks for its device images beside src/engine, where the
// build copies them; in the checkout they sit in assets/bezels.
// build copies them; in the package they sit in assets/bezels.
const from = `/@fs${root}/src/engine/bezels/`;
server.middlewares.use((req, _res, next) => {
if (req.url?.startsWith(from)) {
Expand All @@ -51,10 +30,10 @@ function localDevknobs(): Plugin {
next();
});
},
// Before Vite's own `?raw` loader, which would read the npm package's dist.
// Before Vite's own `?raw` loader, which would read the package's dist.
enforce: 'pre',
async load(id) {
if (!root || !/\/devknobs\/dist\/early\.global\.js\?raw$/.test(id)) {
if (id !== early) {
return;
}
const result = await build({
Expand All @@ -80,14 +59,15 @@ function localDevknobs(): Plugin {
}
return `export default ${JSON.stringify(chunk.code)};`;
},
name: 'local-devknobs',
name: 'devknobs-source',
resolveId: (id) => (id === 'devknobs/early?raw' ? early : undefined),
};
}

export default defineConfig({
plugins: [
tuneEndpoint(resolve(import.meta.dirname, '.tune')),
localDevknobs(),
devknobsSource(),
cloudflare({ viteEnvironment: { name: 'ssr' } }),
tanstackStart(),
react({ compiler: true }),
Expand Down
2 changes: 1 addition & 1 deletion docs/adr/0002-panel-tokens.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,5 @@ ADR-0001 chose black/white plus 3 grays, a 4px radius and Suisse Intl (fetched,
## Consequences

- Suisse Intl and the Inter fallback are dropped, with the font pipeline that served them: `fonts.css`, `@fontsource-variable/inter`, `scripts/fetch-fonts.sh`, `pnpm fonts` and the deploy step that fetched the files.
- The tokens in `packages/ui/src/tokens.stylex.ts` mirror the values in the panel's stylesheet (`src/ui/styles.ts` in mertbuilds/devknobs). When the panel's values change, update the tokens to match.
- The tokens in `packages/ui/src/tokens.stylex.ts` mirror the values in the panel's stylesheet (`packages/devknobs/src/ui/styles.ts`). When the panel's values change, update the tokens to match.
- The 4px spacing scale from ADR-0001 stays.
4 changes: 4 additions & 0 deletions lefthook.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,14 @@ pre-commit:
jobs:
- name: oxlint
glob: '*.{ts,tsx,js,jsx}'
exclude:
- 'packages/devknobs/**'
run: pnpm exec oxlint --fix {staged_files}
stage_fixed: true
- name: oxfmt
glob: '*.{ts,tsx,js,jsx,json,jsonc,yaml,yml,md}'
exclude:
- 'packages/devknobs/**'
run: pnpm exec oxfmt {staged_files}
stage_fixed: true

Expand Down
2 changes: 2 additions & 0 deletions oxfmt.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ export default defineConfig({
'.wrangler',
'pnpm-lock.yaml',
'.claude/skills',
// devknobs keeps its own style and checks (bun test, tsc).
'packages/devknobs',
],
singleQuote: true,
});
2 changes: 2 additions & 0 deletions oxlint.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ export default defineConfig({
'apps/web/src/routeTree.gen.ts',
'apps/web/worker-configuration.d.ts',
'.claude/skills',
// devknobs keeps its own style and checks (bun test, tsc).
'packages/devknobs',
],
overrides: [
{
Expand Down
4 changes: 4 additions & 0 deletions packages/devknobs/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
node_modules
dist
dist.tmp
__pycache__/
Loading
Loading