-
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdocs-pages.js
More file actions
2346 lines (1964 loc) · 216 KB
/
Copy pathdocs-pages.js
File metadata and controls
2346 lines (1964 loc) · 216 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
// ========================================================
// Mainstream docs — page registry
// Each page: { id, group, title, lede, icon (svg path or 'name'), body: HTML string }
// ========================================================
// tiny helpers for inline SVG icons (sidebar + cards)
const I = {
home: '<path d="M3 12 12 4l9 8"/><path d="M5 10v10h14V10"/>',
rocket: '<path d="M5 13c0-5 6-10 14-10 0 8-5 14-10 14l-4-4Z"/><path d="M9 16l-4 4"/><circle cx="15" cy="9" r="1.5"/>',
disc: '<circle cx="12" cy="12" r="9"/><circle cx="12" cy="12" r="3"/>',
sliders: '<line x1="4" y1="7" x2="20" y2="7"/><circle cx="9" cy="7" r="2"/><line x1="4" y1="17" x2="20" y2="17"/><circle cx="15" cy="17" r="2"/>',
wrench: '<path d="M20 7a5 5 0 0 1-6.6 4.7L7 18a2.1 2.1 0 0 1-3-3l6.3-6.3A5 5 0 0 1 16 2l-2.8 2.8 2.5 2.5L18.5 4.5A5 5 0 0 1 20 7Z"/>',
apps: '<rect x="4" y="4" width="6.5" height="6.5" rx="1.5"/><rect x="13.5" y="4" width="6.5" height="6.5" rx="1.5"/><rect x="4" y="13.5" width="6.5" height="6.5" rx="1.5"/><rect x="13.5" y="13.5" width="6.5" height="6.5" rx="1.5"/>',
laptop: '<rect x="5" y="5" width="14" height="10" rx="1.5"/><path d="M3 18h18"/>',
gpu: '<rect x="3" y="7" width="18" height="10" rx="1.5"/><circle cx="9" cy="12" r="2.5"/><path d="M15 12h3"/><path d="M6 17v3M12 17v3M18 17v3"/>',
wifi: '<path d="M5 12a11 11 0 0 1 14 0"/><path d="M8.5 15a6 6 0 0 1 7 0"/><circle cx="12" cy="18" r="1"/>',
bluetooth:'<path d="M8 6l8 6-4 3v-12l4 3-8 6"/>',
bar: '<rect x="3" y="5" width="18" height="3" rx="1"/><rect x="3" y="13" width="10" height="8" rx="1.5"/><rect x="15" y="13" width="6" height="8" rx="1.5"/>',
iface: '<rect x="3" y="4" width="18" height="16" rx="2"/><path d="M3 9h18"/>',
bg: '<rect x="3" y="3" width="18" height="18" rx="2"/><path d="M3 14l5-4 4 3 4-5 5 5"/>',
themes: '<path d="M12 3a9 9 0 0 0 0 18c5 0 4-4 6-5s3-3 3-5a9 9 0 0 0-9-8Z"/><circle cx="7" cy="10" r="1"/><circle cx="10" cy="6.5" r="1"/><circle cx="15" cy="6.5" r="1"/>',
display: '<rect x="3" y="4" width="18" height="12" rx="2"/><path d="M8 20h8"/><path d="M12 16v4"/>',
layout: '<rect x="3" y="3" width="7" height="18" rx="1.5"/><rect x="12" y="3" width="9" height="8" rx="1.5"/><rect x="12" y="13" width="9" height="8" rx="1.5"/>',
mouse: '<rect x="6" y="3" width="12" height="18" rx="6"/><path d="M12 7v4"/>',
power: '<path d="M7 8a7 7 0 1 0 10 0"/><path d="M12 3v9"/>',
user: '<circle cx="12" cy="8" r="4"/><path d="M4 21c0-4 4-7 8-7s8 3 8 7"/>',
gear: '<circle cx="12" cy="12" r="3"/><path d="M12 2v3M12 19v3M2 12h3M19 12h3M5 5l2 2M17 17l2 2M5 19l2-2M17 7l2-2"/>',
update: '<path d="M3 12a9 9 0 0 1 15-6l3-3v6h-6"/><path d="M21 12a9 9 0 0 1-15 6l-3 3v-6h6"/>',
recover: '<path d="M9 3h6l1 4-2 2h-4l-2-2 1-4Z"/><path d="M8 10v11h8V10"/><path d="M10 14h4M10 17h4"/>',
quick: '<circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/>',
overview:'<rect x="3" y="3" width="8" height="8" rx="1"/><rect x="13" y="3" width="8" height="8" rx="1"/><rect x="3" y="13" width="8" height="8" rx="1"/><rect x="13" y="13" width="8" height="8" rx="1"/>',
limine: '<rect x="3" y="4" width="18" height="14" rx="2"/><path d="M7 9h3M7 12h6M7 15h4"/>',
film: '<rect x="3" y="4" width="18" height="16" rx="2"/><path d="M3 8h18M3 16h18M8 4v16M16 4v16"/>',
cam: '<rect x="3" y="6" width="14" height="12" rx="2"/><path d="M17 10l4-2v8l-4-2"/>',
game: '<rect x="2" y="7" width="20" height="10" rx="4"/><circle cx="8" cy="12" r="1"/><circle cx="16" cy="12" r="1.5"/><path d="M6 10v4M4 12h4"/>',
book: '<path d="M4 4h10a4 4 0 0 1 4 4v12H8a4 4 0 0 1-4-4Z"/><path d="M4 4a4 4 0 0 1 4 4v12"/>',
dock: '<rect x="2" y="13" width="20" height="7" rx="3"/><circle cx="7" cy="16.5" r="1"/><circle cx="12" cy="16.5" r="1"/><circle cx="17" cy="16.5" r="1"/>',
keyboard:'<rect x="2" y="6" width="20" height="12" rx="2"/><path d="M6 10h.01M10 10h.01M14 10h.01M18 10h.01M6 14h12"/>',
info: '<circle cx="12" cy="12" r="9"/><path d="M12 11v5M12 8h.01"/>',
shield: '<path d="M12 3l7 3v6c0 4.4-3 7.6-7 9-4-1.4-7-4.6-7-9V6l7-3z"/><path d="M9 12l2 2 4-4"/>',
check: '<circle cx="12" cy="12" r="9"/><path d="M8.5 12.5l2.5 2.5 4.5-5"/>',
fingerprint: '<path d="M8 20c1.5-2.5 2-5 2-8a2 2 0 0 1 4 0c0 3-.4 5.8-1.4 8.4"/><path d="M6 16.5c.7-1.5 1-3 1-4.5a5 5 0 0 1 10 0c0 1.2-.1 2.4-.3 3.5"/><path d="M4.8 12A7.2 7.2 0 0 1 12 4.8c2.7 0 5 1.4 6.3 3.6"/>',
play: '<path d="M8 5.5v13l11-6.5z"/>',
dpad: '<path d="M9 4h6v5h5v6h-5v5H9v-5H4V9h5V4Z"/>',
lock: '<rect x="4" y="11" width="16" height="9" rx="2"/><path d="M8 11V7a4 4 0 0 1 8 0v4"/>',
sidebar: '<rect x="3" y="4" width="18" height="16" rx="2"/><path d="M15 4v16"/>',
send: '<path d="M22 2 11 13"/><path d="M22 2 15 22l-4-9-9-4Z"/>',
tag: '<path d="M3 12V4h8l9 9-8 8-9-9Z"/><circle cx="7.5" cy="7.5" r="1.25"/>',
};
const icon = (name) => `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round">${I[name] || I.disc}</svg>`;
// Shot helper
const shot = (src, alt, cap) => `
<figure>
<div class="shot">
<img src="assets/docs/${src}" alt="${alt}"/>
</div>
${cap ? `<figcaption>${cap}</figcaption>` : ''}
</figure>`;
const twoShot = (a, ac, b, bc) => `
<div style="display:grid;grid-template-columns:1fr 1fr;gap:14px;max-width:1000px;margin:0 0 32px">
<figure style="margin:0"><div class="shot"><img src="assets/docs/${a}" alt=""/></div>${ac ? `<figcaption>${ac}</figcaption>` : ''}</figure>
<figure style="margin:0"><div class="shot"><img src="assets/docs/${b}" alt=""/></div>${bc ? `<figcaption>${bc}</figcaption>` : ''}</figure>
</div>`;
const callout = (kind, title, body) => `
<div class="callout ${kind}">
<div class="ic">${ kind==='note'?'i':kind==='tip'?'✓':kind==='warn'?'!':'✦'}</div>
<div class="callout-body">
<div class="callout-title">${title}</div>
${body}
</div>
</div>`;
// ========================================================
// PAGES
// ========================================================
const PAGES = {};
// ---------- HOME ----------
PAGES.home = {
group: 'Start here',
title: 'Mainstream',
icon: 'home',
navTitle: 'Welcome',
render: () => `
<div class="home-hero">
<div class="left">
<div class="eye">Mainstream Docs · 1.0.4</div>
<h1>A desktop that <em>flows</em> with you.</h1>
<p class="sub">Everything you need to install, configure, and live inside Mainstream — the Arch-based Hyprland distribution built for every home. Set it up once, tune it any time.</p>
<div class="cta-row">
<a class="btn stream" href="#install-iso">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 3v12"/><path d="m6 10 6 6 6-6"/><path d="M4 21h16"/></svg>
Install Mainstream
</a>
<a class="btn ghost" href="#quick">Open settings tour</a>
</div>
</div>
<div class="right">
<div class="hero-pill"><div class="ic">${icon('disc')}</div><div><b>Bootable ISO</b><span>Flash it, boot it, done — no prior Linux knowledge required.</span></div></div>
<div class="hero-pill"><div class="ic">${icon('rocket')}</div><div><b>One-line script install</b><span>Onto any fresh Arch system in under 10 minutes.</span></div></div>
<div class="hero-pill"><div class="ic">${icon('recover')}</div><div><b>Snapshot-protected updates</b><span>Every update is a Btrfs snapshot. Roll back from Limine at any time.</span></div></div>
</div>
</div>
<div class="sec-lbl"><h3>Get started</h3></div>
<div class="card-grid">
${card('install-iso','Install from ISO','disc','Download the live image, flash to USB, boot and click through.', true)}
${card('install-script','Install via script','rocket', 'Run one command on any fresh Arch install. Takes ~10 minutes.', true)}
${card('quick','Quick settings','quick','The first place to go: wallpaper, colors, bar position, and theme mode.')}
</div>
<div class="sec-lbl"><h3>The desktop</h3><a href="#desktop">Take the tour →</a></div>
<div class="card-grid">
${card('desktop','The Desktop','iface','The bar, the dock, and title bars — the pieces you live with every day.', true)}
${card('overview-launcher','Overview & Launcher','overview','A zoomed-out map of every workspace and a launcher that finds everything.')}
${card('sidebars','Sidebars','sidebar','Intelligence on the left; toggles, notifications, and calendar on the right.')}
${card('sharing','Sharing','send','Send and receive files with any device on your network — no cloud.')}
${card('desktop-apps','Desktop Apps','dock','Auto Drive Mount and Uninstall Apps: system chores without a terminal.')}
</div>
<div class="sec-lbl"><h3>Settings reference</h3><a href="#quick">Open settings →</a></div>
<div class="card-grid">
${card('bar','Bar', 'bar', 'Position, pills, workspaces, weather, tray.')}
${card('interface','Interface','iface', 'Decorations, dock, sidebars, fonts, lock screen.')}
${card('background','Background','bg', 'Wallpaper panning, clock widget, weather widget.')}
${card('themes','Themes', 'themes', 'Snapshot your current look and switch between saved themes.')}
${card('display','Display', 'display', 'Arrangement, modes, scale, HDR, color management.')}
${card('layouts','Layouts', 'layout', 'Dwindle, Master, Scrolling, Monocle, Float — per workspace.')}
${card('mouse','Mouse', 'mouse', 'Pointer speed, acceleration, scroll direction.')}
${card('power','Power', 'power', 'Power modes, suspend, battery thresholds.')}
${card('accounts','Accounts', 'user', 'Users, avatars, shared app settings.')}
${card('services','Services', 'gear', 'Language, music recognition, save paths.')}
${card('update','Update', 'update', 'System updates with automatic safety snapshots.')}
${card('recovery','Recovery', 'recover', 'Rollbacks from Limine and manual restore.')}
${card('security','Security', 'shield', 'Why the AUR is off by default, and the signed [mainstream] repo that replaces it.')}
</div>
<div class="sec-lbl"><h3>Creative & play</h3></div>
<div class="card-grid">
${card('davinci','Set up DaVinci Resolve','film','GPU + OpenCL setup, AV1 hardware encode, and render presets for Resolve Studio.')}
${card('obs','Set up OBS','cam','Native bundle: Wayland game capture, a virtual camera, and GPU encoding.')}
${card('gaming','Setting up Gaming','game','Steam + Proton, GameMode, controllers, Vulkan drivers, and VRR.')}
</div>
`
};
function card(id, title, ic, desc, featured=false) {
return `<a class="doc-card" href="#${id}"${featured?' data-featured="true"':''}>
<div class="ic">${icon(ic)}</div>
<h4>${title}</h4>
<p>${desc}</p>
</a>`;
}
// ---------- INSTALL: SCRIPT ----------
PAGES['install-script'] = {
group: 'Installation', title: 'Install via script', icon: 'rocket',
navTitle: 'Script',
lede: 'One command turns a fresh Arch install into Mainstream. It does two jobs: it installs the same numbered release as the ISO, and with --edge it\'s the only way to run the mainstream branch as it stands, ahead of every release.',
render: () => `
${shot('Mainstream_OS_Script_Install.webp', 'The Mainstream installer running in a terminal', 'The one-command installer runs three idempotent steps — dependencies, permissions and services, then config files.')}
<h2>Before you begin</h2>
<p>You should have a working Arch Linux install with a user account, <code>sudo</code> access, and an internet connection. Mainstream installs Hyprland, Quickshell, GPU drivers (detected automatically for your hardware), and everything else on top.</p>
${callout('info','Fresh install or existing Arch?', '<p>The script is idempotent and safe to rerun — rerunning is also how you move onto a newer release later. We still strongly recommend running it on a <strong>fresh Arch install</strong> the first time. If you already have Hyprland configured, the installer backs up clashing configs to <code>~/original-dots-backup</code> automatically before replacing them.</p>')}
<h2>One-line install</h2>
<p>Open a terminal and run:</p>
<pre><code><span class="c"># Clone and run the Mainstream installer</span>
<span class="k">bash</span> <(<span class="k">curl</span> -fsSL https://mainstreamos.org/install.sh)</code></pre>
<p>Or clone it manually if you'd rather read the script first. A plain clone leaves you on the branch, so check out the newest release tag to match what the one-line command does:</p>
<pre><code><span class="k">git</span> clone --branch mainstream \\
https://github.com/MainstreamOS/dots-hyprland.git
<span class="k">cd</span> dots-hyprland
<span class="k">git</span> checkout "$(<span class="k">git</span> tag | grep -E '^[0-9]{1,2}\\.[0-9]+\\.[0-9]+$' | sort -V | tail -1)"
./setup install</code></pre>
<h2>Install options</h2>
<p>Add any of these flags after <code>./setup install</code> to change how — and what — the installer sets up. To use them with the one-line command, put them after a <code>--</code> separator. Run <code>./setup install -h</code> for the full list.</p>
<ul>
<li><code>--os-only</code> — installs just the Mainstream desktop and <strong>skips the bundled default apps</strong> (the Mainstream extras). Mirrors the ISO's "OS Only" method and never removes packages you already installed — pick this to bring your own browser, editor, and utilities.</li>
<li><code>--console</code> — the <strong>gaming / console install</strong>: adds Steam and the 32-bit gaming stack, <strong>boots straight into the Steam gamescope session</strong>, and pre-fetches the Steam Deck client so the first launch is instant. Mirrors the ISO's "Console" method.</li>
<li><code>--verbose</code> — runs the installer in <strong>interactive mode</strong> instead of the default clean visual view: it asks <em>"confirm every command before it runs?"</em>, then lets you approve each step. Handy for auditing exactly what runs, or for troubleshooting a step that failed.</li>
</ul>
<pre><code><span class="c"># all optional — plain ./setup install is the full desktop</span>
./setup install --os-only
./setup install --console
./setup install --verbose
<span class="c"># with the one-liner, flags go after "--"</span>
<span class="k">bash</span> <(<span class="k">curl</span> -fsSL https://mainstreamos.org/install.sh) -- --console</code></pre>
<p>Whichever method you pick, the installer echoes it back in its headers — e.g. <strong>Mainstream installer · --console</strong> — so you can confirm at a glance that the right one is running.</p>
<h2>Release or edge</h2>
<p>By default the script installs the newest numbered release — the same one the ISO ships, and the same one <a href="#update">Settings → Update</a> moves you to. Pass <code>--edge</code> and it installs the <code>mainstream</code> branch as it stands instead: every desktop, settings, and tooling change that has landed since that release, sometimes before it's finished or documented.</p>
<pre><code><span class="c"># newest release — the default</span>
<span class="k">bash</span> <(<span class="k">curl</span> -fsSL https://mainstreamos.org/install.sh)
<span class="c"># the branch as it stands, ahead of every release</span>
<span class="k">bash</span> <(<span class="k">curl</span> -fsSL https://mainstreamos.org/install.sh) --edge
<span class="c"># --edge combines with the install options above</span>
<span class="k">bash</span> <(<span class="k">curl</span> -fsSL https://mainstreamos.org/install.sh) --edge -- --console</code></pre>
<p>The installer prints the channel in its header, so you can see which one you're on. Rerun the command any time to move forward on either channel. <a href="#update">Settings → Update</a> always follows the numbered releases, so on an edge install it stays quiet until a release catches up to where you already are.</p>
<h2>What the script does</h2>
<ol>
<li>Enables the signed <code>[mainstream]</code> package repository.</li>
<li>Installs the Hyprland + Quickshell desktop stack.</li>
<li>Detects your graphics card and installs drivers that match it — AMD, Intel, or NVIDIA, including older NVIDIA cards back to the GeForce 400 series (experimental).</li>
<li>Enables the Bluetooth, network discovery (Avahi), CUPS printing, and audio services.</li>
<li>On qualifying systems (UEFI + Btrfs) replaces the bootloader with Limine and configures Snapper — automatic snapshots before every update, restorable from the boot menu. In <code>--verbose</code> mode you're asked before this step.</li>
<li>Replaces your configs with the Mainstream dotfiles (clashing files are backed up to <code>~/original-dots-backup/</code> first).</li>
</ol>
<h2>Reboot and go</h2>
<p>When the script finishes, reboot. You'll land on the Mainstream login screen. Pick your user, enter your password, and the desktop will be ready.</p>
${callout('tip','Troubleshooting', '<p>If your screen is black after reboot, switch to a TTY with <code>Ctrl</code>+<code>Alt</code>+<code>F2</code> and check <code>journalctl -xb</code>.</p>')}
<h2>First boot</h2>
<p>On first boot the <strong>Welcome</strong> app opens and does three jobs. First, it offers a few quick options to get your desktop personalized and shares some info about the OS. Next, a page gives you one-click installs for some of the most wanted — but normally more involved — user experiences: Gaming, Video Editing, and Content Creation. Then a short tour teaches you how to use the desktop with little practice exercises: switching workspaces, using the dock and app drawer, dragging apps and files between workspaces, and where Files, Settings, and the App Store live.</p>
<p>All of it is skippable and nothing is final: every choice lives in <a href="#quick">Settings</a> too, and you can reopen the tour any time from the app grid.</p>
<h2>Changing graphics cards</h2>
<p>If you swap in a different graphics card later, run <code>gpu-drivers</code> from a terminal — it re-detects the GPU and installs the matching drivers, no password needed. Reboot afterward.</p>
<h2>Updating later</h2>
<p>After a release install, updates go through <strong>Settings → Update</strong> or <code>sudo mainstream-update-helper</code> from a terminal, and you never need to run the installer again.</p>
<p>On an edge install it's the other way round: rerunning the one-line command with <code>--edge</code> is what moves you forward. <strong>Settings → Update</strong> still tracks the numbered releases, so it waits until a release reaches you and then offers to put you back on the release line.</p>
`
};
// ---------- INSTALL: ISO ----------
PAGES['install-iso'] = {
group: 'Installation', title: 'Install from ISO', icon: 'disc',
navTitle: 'ISO',
lede: 'No Linux experience required. Download the Mainstream live image, flash it to a USB stick, and the installer walks you through disk setup, user creation, and first boot.',
render: () => `
${shot('Install_Welcome_Screen.webp','Mainstream installer welcome screen','The Mainstream installer. The sidebar is the whole journey — Welcome, Location, Keyboard, Partitions, Users, Get Started, Apps, then a Summary before anything touches your disk.')}
<h2>Download</h2>
<p>Grab the latest ISO from <a href="https://mainstreamos.org/download" style="color:var(--stream-a);text-decoration:underline">mainstreamos.org/download</a>. Every image is signed — <a href="#verify" style="color:var(--stream-a);text-decoration:underline">verifying your download</a> takes about thirty seconds and proves it\'s exactly what we published.</p>
<table class="t">
<thead><tr><th>Image</th><th>Size</th><th>Best for</th></tr></thead>
<tbody>
<tr><td><a href="https://sourceforge.net/projects/mainstreamos/files/" style="color:var(--stream-a);text-decoration:underline"><b>mainstream-x.x.x.iso</b></a></td><td>3.5 GB</td><td>Most modern laptops & desktops</td></tr>
<tr><td><a href="https://sourceforge.net/projects/mainstreamos/files/legacy-nvidia/" style="color:var(--stream-a);text-decoration:underline"><b>mainstream-legacy-nvidia-x.x.x.iso</b></a></td><td>4.8 GB</td><td>Older NVIDIA cards, back to the GeForce 400 series (experimental)</td></tr>
<tr><td><a href="https://sourceforge.net/projects/mainstreamos/files/macbook/" style="color:var(--stream-a);text-decoration:underline"><b>mainstream-macbook-x.x.x.iso</b></a></td><td>3.5 GB</td><td>Intel Macs with Apple's T2 chip, 2018 to 2020 (experimental). Earlier Macs take the standard image</td></tr>
</tbody>
</table>
${callout('note','All versions & checksums','<p>Looking for a specific release, the experimental legacy-NVIDIA or MacBook editions, or the <code>.sha256</code> and signature files? Browse <a href="https://sourceforge.net/projects/mainstreamos/files/" style="color:var(--stream-a);text-decoration:underline">every download on SourceForge</a>.</p>')}
<h2>Flash to USB</h2>
<p>Flash the downloaded ISO file to a USB stick. Any USB stick 8 GB or larger works.</p>
<p>Any of these apps can do it. If one of their icons looks familiar, you may already have it installed:</p>
<div class="flash-grid">
<a class="flash-app" href="https://etcher.balena.io"><img src="assets/flash-apps/etcher.png" alt="balenaEtcher icon"/><span class="fa-name">balenaEtcher</span><span class="fa-rec">Recommended</span><span class="fa-plat">Linux · macOS · Windows</span></a>
<a class="flash-app" href="https://www.ventoy.net"><img src="assets/flash-apps/ventoy.png" alt="Ventoy icon"/><span class="fa-name">Ventoy</span><span class="fa-plat">Linux · Windows</span></a>
<a class="flash-app" href="https://rufus.ie"><img src="assets/flash-apps/rufus.png" alt="Rufus icon"/><span class="fa-name">Rufus</span><span class="fa-plat">Windows · pick DD mode</span></a>
<a class="flash-app" href="https://apps.gnome.org/Impression/"><img src="assets/flash-apps/impression.png" alt="Impression icon"/><span class="fa-name">Impression</span><span class="fa-plat">Linux</span></a>
<a class="flash-app" href="https://apps.gnome.org/DiskUtility/"><img src="assets/flash-apps/gnome-disks.svg" alt="GNOME Disks icon"/><span class="fa-name">GNOME Disks</span><span class="fa-plat">Linux</span></a>
</div>
<h2>Turn off Microsoft's Secure Boot feature</h2>
<p>Most computers will only start operating systems Microsoft has signed, a setting called <strong>Secure Boot</strong>. Mainstream isn\'t on that list, so switch it off first or the machine will ignore your USB stick. This is normal for Linux installs; nothing is wrong with your download.</p>
<ol>
<li><strong>Restart</strong> and tap the BIOS key while the machine powers on. It is usually <code>F2</code>; HP uses <code>F10</code>, most desktops use <code>Del</code>, and many machines show the key on screen for a moment.</li>
<li><strong>Find Secure Boot</strong>, usually under a <strong>Security</strong> or <strong>Boot</strong> tab, and set it to <strong>Disabled</strong>.</li>
<li><strong>Save and exit</strong>, usually <code>F10</code>. The computer restarts.</li>
</ol>
<p>That\'s the whole job. Boot from the USB stick and carry on, and leave Secure Boot off afterwards: Mainstream needs it off after the install too.</p>
${callout('warn','If you have a Windows install you want to keep, or you want to dual boot','<p>If Windows is encrypted with BitLocker, changing Secure Boot can make it ask for the <strong>BitLocker recovery key</strong> the next time it starts. Save yours first at <a href="https://aka.ms/myrecoverykey" style="color:var(--stream-a);text-decoration:underline">aka.ms/myrecoverykey</a>. If Windows asks later, you type it in once and everything carries on as normal.</p>')}
<h2>Boot the installer</h2>
<p>Plug the USB into your computer and boot it (you may need to press <code>F12</code>, <code>F2</code>, or <code>Del</code> to pick the boot device). On the boot menu select <strong>Mainstream OS - Live (default)</strong>, wait for the desktop. A Welcome app appears where you can set your resolution and monitor scale, and connect to Wi-Fi if you aren't on Ethernet. Once you've applied your settings, click <strong>Start install</strong>.</p>
<h2>Installer walkthrough</h2>
<p>The welcome screen picks your language — and keeps support, known issues, and release notes one click away. From there the sidebar walks you through every step in order, and nothing is written to disk until you approve the final Summary:</p>
<ol>
<li><b>Location & Keyboard</b> — timezone, region formats, and keyboard layout.</li>
<li><b>Partitions</b> — pick where Mainstream lives (details below).</li>
<li><b>Users</b> — create your account and computer name. This user gets administrator rights.</li>
<li><b>Get Started & Apps</b> — choose the kind of system you want (details below).</li>
<li><b>Summary → Install</b> — one review screen, then it runs on its own: ~8 minutes on an SSD to copy the system, set up the bootloader with snapshot support, and reboot. <br/>(Setup can take much longer if you choose to install a lot of apps during a custom install.)</li>
</ol>
<h3>Pick where Mainstream lives</h3>
${shot('Installer_Partitions_Screen.webp','Partitions step of the installer','Three ways in — shrink another OS and install alongside it, replace a single partition, or erase the whole disk. The Current/After bars preview exactly what will change before you commit.')}
<p>Keeping Windows or another Linux? <strong>Install alongside</strong> shrinks it to make room and both systems appear in the boot menu. Dedicating the machine? <strong>Erase disk</strong> takes it all. Tick <strong>Encrypt system</strong> and the whole install is protected with a passphrase you enter at boot. Either way Mainstream lands on Btrfs, which is what makes the <a href="#recovery">snapshot rollbacks</a> recovery system work out of the box.</p>
<h3>Choose the kind of system you want</h3>
${shot('Installer_Installation_Method_Screen.webp','Get Started step of the installer','Four setups, one click. Default Apps is the right answer for most people — and every choice can be changed later.')}
<div class="props">
<div class="prop"><center><div class="k">Default Apps</div></center><div class="v">Everything needed for a complete desktop, ready out of the box. Ideal for new Linux users and family computers.</div></div>
<div class="prop"><center><div class="k">Customize Your Apps</div></center><div class="v">Hand-pick from a curated selection of popular Linux applications — you choose exactly what gets installed.</div></div>
<div class="prop"><center><div class="k">Console Mode</div></center><div class="v">The same apps as Default, but the computer boots straight into Steam's Big Picture like a game console. A console experience that still allows you to switch to the desktop at any time from the menu.</div></div>
<div class="prop"><center><div class="k">OS Only</div></center><div class="v">A clean slate — just the base system and desktop, for experienced users who like to build their own setup.</div></div>
</div>
<h3>Hand-pick your apps</h3>
${shot('Install_Custom_Install_Screen.webp','Apps step of the installer','Choosing Customize opens the Apps step: recommended extras come pre-selected, and browsers, dev tools, media, office, gaming, creative, streaming, and chat apps are a checkbox each.')}
<p>Only shown if you chose <strong>Customize Your Apps</strong>. <strong>Included Extras</strong> starts checked with the recommended set — uncheck anything you don\'t want, then expand the categories to add more. Everything here downloads and installs from the official Arch Linux repositories or from Mainstream\'s <a href="#security">signed repository</a>, never from third-party sources or the AUR (Arch User Repository).</p>
<h2>First boot</h2>
<p>On first boot the <strong>Welcome</strong> app opens and does three jobs. First, it offers a few quick options to get your desktop personalized and shares some info about the OS. Next, a page gives you one-click installs for some of the most wanted — but normally more involved — user experiences: Gaming, Video Editing, and Content Creation. Then a short tour teaches you how to use the desktop with little practice exercises: switching workspaces, using the dock and app drawer, dragging apps and files between workspaces, and where Files, Settings, and the App Store live.</p>
<p>All of it is skippable and nothing is final: every choice lives in <a href="#quick">Settings</a> too, and you can reopen the tour any time from the app grid.</p>
${callout('tip','Dual-booting with Windows', '<p>The installer preserves existing operating system entries. After install, Limine will list your other operating systems automatically. If Windows doesn\'t appear, run <code>sudo limine-update</code> from a terminal and reboot.</p>')}
<h2>Running it in a virtual machine</h2>
<p>Mainstream installs in a virtual machine the same way it does on a real one. The display the machine is given is worth checking first, since it is picked in the hypervisor rather than in the installer.</p>
<div class="props">
<div class="prop"><center><div class="k">VirtualBox</div></center><div class="v">Set the graphics controller to <b>VMSVGA</b>, which is the default on current versions. The older <b>VBoxVGA</b> has no modern display driver behind it, and a guest running on it gets unsteady mouse and keyboard input.</div></div>
<div class="prop"><center><div class="k">VMware</div></center><div class="v">Nothing to change. Leave 3D acceleration on if the host offers it.</div></div>
<div class="prop"><center><div class="k">Proxmox, QEMU and KVM</div></center><div class="v">Use the <b>VirtIO-GPU</b> display. SPICE works as well.</div></div>
</div>
<p>The guest tools for VMware, VirtualBox, QEMU and SPICE all ship on the image and start themselves when they recognize the machine they are running on, so there is nothing to install inside the guest.</p>
${callout('note','If the machine will not start','<p>Pick <b>Live (Safe graphics)</b> from the boot menu. It skips graphics mode setting altogether and comes up on a plain framebuffer, which is enough to run the installer.</p>')}
<h2>Changing graphics cards</h2>
<p>If you swap in a different graphics card later, run <code>gpu-drivers</code> from a terminal — it re-detects the GPU and installs the matching drivers, no password needed. Reboot afterward.</p>
<h2>Updating later</h2>
<p>After install, all updates go through <strong>Settings → Update</strong> or <code>sudo mainstream-update-helper</code> from a terminal. You never need to run the installer again.</p>
`
};
// ---------- QUICK ----------
PAGES.quick = {
group: 'Settings', title: 'Quick', icon: 'quick',
lede: 'Quick is the first screen of Settings — the dial-in knobs you\'ll touch most often. Wallpaper, color scheme, bar position, and rounded corners, all in one place.',
render: () => `
<p class="shot-note">The whole page at once. Quick is the everyday entry point, and every control on it has a fuller counterpart deeper in Settings when you want to go further than the shortcut.</p>
${shot('QuickConfig.webp','Quick settings page')}
<h2>Wallpaper & Colors</h2>
<p>Pick from the built-in wallpapers, or hit <strong>Wallpaper</strong> to use your own — a still image or a video — or <strong>Slideshow</strong> to hand it a whole folder. Mainstream extracts a Material You palette from whatever you pick and propagates the colors through the bar, sidebars, and system apps. Your login screen matches too, color scheme and all — it follows your wallpaper automatically, and each user gets their own, with no separate login background to set.</p>
<div class="props">
<div class="prop"><center><div class="k">Default Wallpaper</div></center><div class="v">Select it to restore the default Mainstream wallpaper at any time.</div></div>
<div class="prop"><center><div class="k">Wallpaper</div></center><div class="v">Pick any image or video. <code>Ctrl</code>+<code>SUPER</code> (the ⊞ Windows or ⌘ Command key)+<code>T</code> is the keyboard shortcut.</div></div>
<div class="prop"><center><div class="k">Slideshow</div></center><div class="v">Point it at a folder instead of one picture and it moves through them on a timer. The palette follows along, so the whole desktop recolors with every change. Choosing a single wallpaper again ends it.</div></div>
<div class="prop"><center><div class="k">Light / Dark</div></center><div class="v">Hard-switch between Mainstream's warm Day theme and the default Night. Pair with <a href="#interface">Auto theme</a> in Interface settings to follow sunrise/sunset.</div></div>
<div class="prop"><center><div class="k">Palette style</div></center><div class="v"><span class="tag">Auto</span> <span class="tag">Content</span> <span class="tag">Expressive</span> <span class="tag">Fidelity</span> <span class="tag">Fruit Salad</span> <span class="tag">Monochrome</span> <span class="tag">Neutral</span> <span class="tag">Rainbow</span> <span class="tag">Tonal Spot</span><br/>Different Material You tonal maps. Expressive pops color the most; Monochrome strips it entirely.</div></div>
<div class="prop"><center><div class="k">Transparency</div></center><div class="v">Toggles translucent surfaces (sidebars, notifications, dock). Turn off if you\'re on a slower GPU or prefer flat surfaces.</div></div>
</div>
<h2>Bar & screen</h2>
<p>The quick path to moving the bar around. For every option (workspace indicators, utility buttons, weather, tray, clock format) jump to the full <a href="#bar">Bar</a> page.</p>
<div class="props">
<div class="prop"><center><div class="k">Bar position</div></center><div class="v"><b>Top</b> (default) · <b>Left</b> · <b>Bottom</b> · <b>Right</b></div></div>
<div class="prop"><center><div class="k">Bar style</div></center><div class="v"><span class="tag">Hug</span> touches the screen edges. <span class="tag">Float</span> (default) floats with a gap around it. <span class="tag">Rect</span> is a flat rectangle. <span class="tag">Notch</span> sits on the edge with a curve drawn where each end leaves it, so the bar reads as grown out of the screen edge rather than laid on top of it.</div></div>
<div class="prop"><center><div class="k">Screen round corner</div></center><div class="v">Draws subtle rounded corners at the edges of your monitor. <b>When not fullscreen</b> disables them automatically while a window is fullscreened.</div></div>
</div>
`
};
// ---------- WIFI ----------
PAGES.wifi = {
group: 'Settings', title: 'Wi-Fi', icon: 'wifi',
lede: 'Scan, connect, and manage saved Wi-Fi networks. Uses NetworkManager under the hood so any command-line tool you already know still works.',
render: () => `
<p class="shot-note">Networks in range, with the one you are on at the top. Everything below follows this order: joining a network first, then reading what the list is telling you.</p>
${shot('WiFiConfig.webp','Wi-Fi settings page')}
<h2>Connecting to a network</h2>
<ol>
<li>Toggle <strong>Enable Wi-Fi</strong> on.</li>
<li>Hit <strong>Scan</strong> to refresh the list.</li>
<li>Click any network to expand it. Enter the password and hit Connect.</li>
<li>Tick <strong>Connect automatically</strong> to save it as a preferred network.</li>
</ol>
<h2>Reading the network list</h2>
<p>Each row shows the SSID, security type, and band at a glance:</p>
<ul>
<li><b>WPA2</b> / <b>WPA3</b> / <b>Open</b> — security. Prefer WPA3 when both are available.</li>
<li><b>2.4 GHz</b> vs <b>5 GHz</b> — 5 GHz is faster but has shorter range. Most routers broadcast both.</li>
<li>The signal icon fills from 1 to 4 bars. Mainstream de-emphasizes networks below 2 bars.</li>
</ul>
<h2>Hidden networks & enterprise Wi-Fi</h2>
<p>Scroll to the bottom of the list. <strong>Add hidden network</strong> lets you enter the SSID manually. <strong>Enterprise (802.1x)</strong> opens a form with identity, anonymous identity, CA cert, and inner auth — useful for university and corporate networks.</p>
`
};
// ---------- BLUETOOTH ----------
PAGES.bluetooth = {
group: 'Settings', title: 'Bluetooth', icon: 'bluetooth',
lede: 'Pair headphones, keyboards, speakers, and controllers.',
render: () => `
<p class="shot-note">The adapter, the devices it knows about, and the ones it can see right now. Pairing comes first below, then the modes that decide what is discoverable.</p>
${shot('BluetoothConfig.webp','Bluetooth settings page')}
<h2>Pairing a device</h2>
<ol>
<li>Flip <strong>Enable Bluetooth</strong> on if it isn\'t already.</li>
<li>Put your device in pairing mode (usually hold the power button for 3-5 seconds).</li>
<li>The device appears in <strong>Available Devices</strong>. Click it, hit <strong>Pair</strong>, confirm the PIN if prompted.</li>
</ol>
<h2>Modes</h2>
<div class="props">
<div class="prop"><center><div class="k">Enable Bluetooth</div></center><div class="v">Master power switch. The Bluetooth icon in the top bar mirrors this state.</div></div>
<div class="prop"><center><div class="k">Discoverable</div></center><div class="v">Makes <em>this</em> machine visible to other devices. Turn on only when you\'re sending files or using the machine as a speaker.</div></div>
<div class="prop"><center><div class="k">Pairable</div></center><div class="v">Controls whether other devices can initiate pairing with you. Independent of Discoverable.</div></div>
</div>
<h2>Device management</h2>
<p>Click any paired device in the list to expand it. You\'ll get:</p>
<ul>
<li><b>Connect / Disconnect</b> — toggle the active connection without forgetting the device.</li>
<li><b>Pair / Forget</b> — one tap pairs a new device, connects it, and trusts it so it reconnects on its own from then on. <b>Forget</b> removes the pairing entirely — the device goes back to the Available list, ready to pair fresh.</li>
</ul>
${callout('note','Gaming controllers', '<p>DualShock, DualSense, Xbox, and most 8BitDo pads pair natively. See the <a href="#gaming">Gaming</a> page for tuning and vibration fixes.</p>')}
`
};
// ---------- BAR ----------
PAGES.bar = {
group: 'Settings', title: 'Bar', icon: 'bar',
lede: 'The top bar is Mainstream\'s status center. Everything from workspace indicators to GPS weather to utility buttons lives here, and every module can be toggled or repositioned.',
render: () => `
<p class="shot-note">The top of the page: the widget catalog you arrange the bar from, then the clock formats and where the bar sits.</p>
${shot('BarConfig-1.webp','Widget layout, Time and Date, and Positioning')}
<h2>Widget layout</h2>
<p>The bar is built from widgets you arrange yourself. There are two ways to go about it:</p>
<div class="props">
<div class="prop"><center><div class="k">Simple</div></center><div class="v">The stock arrangement. Everything sits where Mainstream put it and you only decide what is shown.</div></div>
<div class="prop"><center><div class="k">Custom</div></center><div class="v">Take over completely. Drag widgets to reorder them or move them between the left, center, and right sections — top, middle, and bottom on a vertical bar. Tap a widget to hide it, and it stays hidden until you put it back.</div></div>
</div>
<p>The catalog carries two window-title widgets: the plain one, drawn bare on the strip, and <strong>Window title (pill)</strong>, drawn on a pill like its neighbours, which starts to matter once the strip itself can be seen through. Both ship in the default layout with the pill one switched off, so existing bars look unchanged until you turn it on. Neither is offered while the bar is vertical.</p>
<p>Drop one widget against another to <strong>group them into a pill</strong> — a single rounded container holding both, which is how the clock and its neighbours are drawn by default. <strong>Group style</strong> switches between pills and plain spacing. <strong>Reset to default layout</strong> puts everything back.</p>
${callout('note','Vertical bars leave some widgets out', '<p>A few widgets only make sense across the top. The update indicator, for one, isn\'t offered when the bar is vertical.</p>')}
<h2>Time & Date</h2>
<div class="props">
<div class="prop"><center><div class="k">Time Format</div></center><div class="v"><span class="tag">24h</span> 14:32 <span class="tag">12h am/pm</span> 2:32 pm <span class="tag">12h AM/PM</span> 2:32 PM (default)</div></div>
<div class="prop"><center><div class="k">Date Format</div></center><div class="v"><span class="tag">Date First</span> 20/04 <span class="tag">Month First</span> 04/20 (default)</div></div>
</div>
<h2>Positioning</h2>
<div class="props">
<div class="prop"><center><div class="k">Bar position</div></center><div class="v"><b>Top</b> is default. Left/Right orient the bar vertically — handy on ultrawide monitors. Bottom is classic macOS/Chrome OS.</div></div>
<div class="prop"><center><div class="k">Automatically hide</div></center><div class="v">When <b>Yes</b>, the bar slides away when a window touches it and reappears on hover. Great for fullscreen work.</div></div>
<div class="prop"><center><div class="k">Corner style</div></center><div class="v"><span class="tag">Hug</span> flush to the screen edge. <span class="tag">Float</span> floats with margin on all sides (default). <span class="tag">Rect</span> full-width rectangle, no rounding. <span class="tag">Notch</span> sits down on the edge and curves away from it, so the screen edge appears to fold around the bar. It starts opaque and fully rounded, and keeps its own width apart from Float’s, so moving between the two does not carry one width over to the other.</div></div>
<div class="prop"><center><div class="k">Group style</div></center><div class="v"><span class="tag">Pills</span> separate clusters for each module group (default). <span class="tag">Line-separated</span> one continuous bar split by thin dividers.</div></div>
</div>
<p class="shot-note">Everything that decides what the bar looks like rather than what it holds: its shape, how far through it you can see, and its color.</p>
${shot('BarConfig-2.webp','Shape, Transparency and Colors')}
<h2>Shape</h2>
<p>These apply to the shapes that leave the screen edge, <b>Float</b> and <b>Notch</b>. A hugging or rectangular bar has no gap to size and no corners to round, so they are not offered for it.</p>
<div class="props">
<div class="prop"><center><div class="k">Split into three</div></center><div class="v">Draws the left, center and right clusters as three separate strips with the desktop showing between them, instead of one continuous strip. Off by default. With it on, the slider below becomes <b>Spread</b> and sets how far the outer two sit from the middle one.</div></div>
<div class="prop"><center><div class="k">Width</div></center><div class="v">How far across the screen the floating strip reaches. Narrowing it carries the end clusters inward with the edges they are pinned to. The bottom of the track moves with how crowded the bar is, so a busy bar cannot be squeezed past what its widgets need. Notch stops a little short of full width so its end curves have room in the screen corners.</div></div>
<div class="prop"><center><div class="k">Corner roundness</div></center><div class="v">How rounded the strip’s own corners are, from square to fully pill-shaped. Notch starts at the maximum so it reads as one shape with the dock; Float starts at the roundness the rest of the interface uses.</div></div>
<div class="prop"><center><div class="k">Widget pills</div></center><div class="v">How rounded the widget group pills inside the bar are. Not offered when <b>Group style</b> is Line-separated, since those groups draw no surface to round.</div></div>
</div>
<p><strong>Reset to default shape</strong> hands all four back to the interface in one press, and appears once you have moved any of them. It is not the same as sliding them back onto their marks: a mark is today’s stock number, while the reset says to let the interface decide, which keeps following it if those numbers ever change.</p>
<h2>Transparency</h2>
<div class="props">
<div class="prop"><center><div class="k">Show background</div></center><div class="v">Draws the bar’s surface behind its widgets. Off leaves the widgets floating on the wallpaper with nothing behind them. On by default.</div></div>
<div class="prop"><center><div class="k">Background</div></center><div class="v">How far through that surface you can see, shown while <b>Show background</b> is on. The track stops short of fully clear on purpose: past that point the compositor drops the blur outright rather than easing it away, which reads as a step rather than a fade.</div></div>
<div class="prop"><center><div class="k">Widget pills</div></center><div class="v">How solid the widget group pills are, set apart from the strip behind them. Not offered when <b>Group style</b> is Line-separated.</div></div>
</div>
<p><strong>Reset to default transparency</strong> returns both sliders to following the interface. The tracks cannot express that state on their own, so this is the only way back to it.</p>
<h2>Colors</h2>
<p><strong>Background</strong> gives the strip a color of your own, by swatch or by hex. <strong>Widget pills</strong> does the same for the group pills, set apart from the strip, and is not offered when Group style is Line-separated. Leave either empty and it follows the theme, changing with your wallpaper like everything else. <strong>Reset to default colors</strong> empties every slot at once, which saves working out that an emptied box is how you say you want no color of your own.</p>
${callout('note','Each mode keeps its own colors', '<p>Dark mode and light mode store these separately, so a color picked in one does not follow you into the other. Set them twice if you move between them.</p>')}
<h2>Resource usage module</h2>
<p>Flip this on to show CPU, RAM, and (if detected) GPU usage live in the bar. Clicking the module pops a mini-graph with a 60-second history.</p>
<p class="shot-note">The rest of the page: the workspace indicators, the utility buttons beside them, and the weather section below.</p>
${shot('BarConfig-3.webp','Workspaces, utility buttons and weather')}
<h2>Workspaces</h2>
<div class="props">
<div class="prop"><center><div class="k">Always show numbers</div></center><div class="v">Off by default — only shows the number for the focused workspace. Turn on if you jump between workspaces by number a lot.</div></div>
<div class="prop"><center><div class="k">Show app icons</div></center><div class="v">Draws the icon of whatever app is on each workspace. Quick visual map.</div></div>
<div class="prop"><center><div class="k">Tint app icons</div></center><div class="v">Tints the icons with your Material You accent for a unified look.</div></div>
<div class="prop"><center><div class="k">Large circular app icons</div></center><div class="v">Draws each workspace’s app icon larger and in a circle rather than small and square. Off by default.</div></div>
<div class="prop"><center><div class="k">Workspaces shown</div></center><div class="v">How many workspace dots render in the bar. Default 10.</div></div>
<div class="prop"><center><div class="k">Number show delay</div></center><div class="v">When you hold <code>SUPER</code> (the ⊞ Windows or ⌘ Command key), how long before the number overlay appears on each workspace. Default 300 ms.</div></div>
</div>
<h2>Utility buttons</h2>
<p>Small inline launchers in the bar for everyday actions:</p>
<ul>
<li><b>Screen snip</b> — region screenshot (<code>SUPER</code>+<code>Shift</code>+<code>S</code>).</li>
<li><b>Color picker</b> — eyedropper that copies the hex under your cursor.</li>
<li><b>Keyboard toggle</b> — shows the on-screen keyboard. Useful on touchscreens.</li>
<li><b>Mic toggle</b> — mute/unmute the default source system-wide.</li>
<li><b>Dark/Light toggle</b> — one-click theme flip.</li>
<li><b>Performance Profile toggle</b> — cycles Performance / Balanced / Power Saver.</li>
<li><b>Record</b> — starts a screen recording, with visible recording indicator.</li>
</ul>
<h2>Weather</h2>
<p>Powered by Open-Meteo. When <strong>Enable GPS based location</strong> is on, Mainstream uses GeoClue and the <em>City name</em> field greys out, since your position is coming from the machine rather than from what you typed. Turn it off to name a city yourself. <strong>Polling interval</strong> is how often (in minutes) the widget refreshes.</p>
<div class="props">
<div class="prop"><center><div class="k">Temperature unit</div></center><div class="v"><span class="tag">Automatic</span> the default, taking the unit from wherever you are, so a machine in the US reads Fahrenheit and one elsewhere reads Celsius without anybody setting it. <span class="tag">Celsius</span> <span class="tag">Fahrenheit</span> pin it whatever the location.</div></div>
</div>
<h2>Tray</h2>
<div class="props">
<div class="prop"><center><div class="k">Make icons pinned by default</div></center><div class="v">New status icons (Slack, Discord, Syncthing, etc.) always appear. When off, tray icons live in a collapse menu until you pin them.</div></div>
<div class="prop"><center><div class="k">Tint icons</div></center><div class="v">Recolors tray icons to match your accent. Very polished, but some apps ship non-square icons that tint poorly — turn off if they look odd.</div></div>
</div>
<h2>Volume Control</h2>
<p><strong>Show volume icon in bar</strong> adds a speaker pill. Scroll on it to adjust volume, click to open the mixer, right-click for the output device picker.</p>
`
};
// ---------- DOCK ----------
PAGES.dock = {
group: 'Settings', title: 'Dock', icon: 'dock',
lede: 'The dock is the row of app icons along one edge of the screen. It has a page of its own for where it sits, how it reacts to the pointer, what shape it takes, and what color it is.',
render: () => `
<p class="shot-note">Where the dock sits and how it reacts to the pointer, which is everything under Behavior below.</p>
${shot('DockConfig-1.webp','Dock behavior, and the start of Shape')}
<h2>Behavior</h2>
<div class="props">
<div class="prop"><center><div class="k">Position</div></center><div class="v">Which edge the dock sits on: <span class="tag">Bottom</span> the default <span class="tag">Top</span> <span class="tag">Left</span> <span class="tag">Right</span> <span class="tag">Disabled</span> turns the dock off. On the left or right it stands vertically, icons stacked. Pick the edge your bar is already using and the bar moves to the opposite one, so the two never share a side.</div></div>
<div class="prop"><center><div class="k">Window indicators</div></center><div class="v">The mark under an icon that says the app is running, and how many windows it has. <span class="tag">Dashes</span> the default <span class="tag">Dots</span> <span class="tag">Count badge</span> a number instead of marks, which stays readable past three or four windows <span class="tag">None</span></div></div>
<div class="prop"><center><div class="k">Launch animation</div></center><div class="v">The icon reacts when you start an app, so you can see the click landed before the window appears. <span class="tag">Bounce</span> the default <span class="tag">Pulse</span> <span class="tag">Pop</span> <span class="tag">Wobble</span> <span class="tag">None</span> Only a genuine launch animates: clicking an app that is already open, or opening a folder, does not.</div></div>
<div class="prop"><center><div class="k">Hover animation</div></center><div class="v">What an icon does as the pointer passes over it. <span class="tag">Magnify</span> the icon grows, in the manner of a classic dock <span class="tag">Glow</span> a lit halo instead of a size change <span class="tag">None</span></div></div>
<div class="prop"><center><div class="k">Magnify amount</div></center><div class="v">How far the hovered icon grows. The mark on the track is the stock setting, so you can always find your way back to it.</div></div>
<div class="prop"><center><div class="k">Glow intensity</div></center><div class="v">How strong the halo is. Appears in place of the magnify slider when Glow is the chosen hover animation.</div></div>
<div class="prop"><center><div class="k">Hover to reveal</div></center><div class="v">The dock stays hidden while a window is focused and slides in when your cursor touches the edge it sits on. Off: it only appears on an empty workspace, not on hover.</div></div>
<div class="prop"><center><div class="k">Pinned on startup</div></center><div class="v">Starts the session with the dock pinned open, always visible and reserving its space along its edge, until you unpin it.</div></div>
<div class="prop"><center><div class="k">Show overview button</div></center><div class="v">Puts the overview button on the end of the dock. Turn it off if you open the overview by hot corner or keyboard and would rather have the space.</div></div>
<div class="prop"><center><div class="k">Show pin button</div></center><div class="v">Puts the pin toggle on the dock, so you can hold it open for a while without going to settings.</div></div>
<div class="prop"><center><div class="k">Right-click volume control</div></center><div class="v">Adds a volume slider and mute toggle to the right-click menu of a dock icon for any app currently playing audio. <b>Per window</b> gives each window its own slider, handy for browsers or Discord where different windows play different sound; <b>Per app</b> groups them into one.</div></div>
<div class="prop"><center><div class="k">Tint app icons</div></center><div class="v">Desaturates each icon and washes it with your accent color for a uniform look. Keep off for brand-accurate icons.</div></div>
</div>
<p class="shot-note">The two shapes the right-click menu takes, set by <b>Right-click volume control</b> above: one slider for the app, or one for each of its windows.</p>
${twoShot('Dock-Right-Click-Per-App.webp','Right-click a dock icon, per-app view','Dock-Right-Click-Per-Window.webp','Per-window view, one slider per open window')}
<p class="shot-note">What the dock looks like rather than how it behaves: its shape, how solid its surface is, and its color.</p>
${shot('DockConfig-2.webp','Dock shape, transparency and colors')}
<h2>Shape</h2>
<div class="props">
<div class="prop"><center><div class="k">Corner style</div></center><div class="v"><span class="tag">Float</span> the dock floats clear of the edge with a margin around it, the default <span class="tag">Rect</span> a plain rectangle with no rounding <span class="tag">Notch</span> sits against the edge and curves away from it, so the screen edge appears to fold around the dock.</div></div>
<div class="prop"><center><div class="k">Icon size</div></center><div class="v">How large the app icons are, and with them the dock itself.</div></div>
<div class="prop"><center><div class="k">Corner roundness</div></center><div class="v">How rounded the dock\'s own corners are, from square to fully pill-shaped.</div></div>
</div>
<h2>Transparency</h2>
<div class="props">
<div class="prop"><center><div class="k">Show background</div></center><div class="v">Draws the dock\'s surface behind the icons. Off leaves the icons floating on the wallpaper with nothing behind them.</div></div>
<div class="prop"><center><div class="k">Background</div></center><div class="v">How far through that surface you can see. Slide it down for a dock that reads as part of the wallpaper, up for one that reads as a solid shelf.</div></div>
</div>
<h2>Colors</h2>
<p><strong>Dock background</strong> takes a color of your own, either from the swatch or by typing a hex value. Leave it empty and the dock follows the theme, changing with your wallpaper like everything else.</p>
${callout('note','Each mode keeps its own color', '<p>Dark mode and light mode store the dock color separately, so a color picked in one does not follow you into the other. Set it twice if you switch between them.</p>')}
`
};
// ---------- INTERFACE ----------
PAGES.interface = {
group: 'Settings', title: 'Interface', icon: 'iface',
lede: 'The sidebars, the hot corner, the overviews and the lock screen — the parts of the desktop you reach for, rather than the parts that are simply drawn.',
render: () => `
<p class="shot-note">The top of the page: the hot corner and the two overviews it can open. The dock section that used to sit below them now has a <a href="#dock">page of its own</a>.</p>
${shot('InterfaceConfig-1.webp','The hot corner and the overviews')}
${callout('note','Looking for decorations or fonts?', '<p>Window borders, blur, shadows, rounded corners and title bars — along with your app style, icons, pointer and fonts — now live on their own <a href="#decorations">Decorations</a> page.</p>')}
<h2>Left Hot Corner</h2>
<p>The very top-left corner of the screen is a hot corner — sweep your cursor into it and the overview opens.</p>
<div class="props">
<div class="prop"><center><div class="k">Ripple Animation</div></center><div class="v">The little water-ripple animation that plays when you hit the corner.</div></div>
<div class="prop"><center><div class="k">Trigger overview</div></center><div class="v">What the corner opens: <span class="tag">Default Overview</span> the built-in grid <span class="tag">Scrolling Overview</span> the niri-style panning view <span class="tag">Off</span> disables the corner.</div></div>
</div>
<h3>Scrolling Overview</h3>
<p>Shown when the corner is set to Scrolling Overview.</p>
<div class="props">
<div class="prop"><center><div class="k">Layout</div></center><div class="v">Lay the workspace previews out <b>Vertical</b> or <b>Horizontal</b>.</div></div>
<div class="prop"><center><div class="k">Workspace gap</div></center><div class="v">Pixels between workspace previews. Default 100.</div></div>
<div class="prop"><center><div class="k">Workspace scale</div></center><div class="v">How much each preview shrinks — lower fits more workspaces on screen. Default 50%.</div></div>
</div>
<h2>Launcher Overview</h2>
<p>Settings for the built-in overview grid (<a href="#overview-launcher">Overview & Launcher</a>).</p>
<div class="props">
<div class="prop"><center><div class="k">Enable</div></center><div class="v">Master toggle for the overview.</div></div>
<div class="prop"><center><div class="k">Size (%)</div></center><div class="v">How much of the screen the overview fills.</div></div>
<div class="prop"><center><div class="k">Rows / Columns</div></center><div class="v">The shape of the workspace grid. Default 2 rows by 5 columns.</div></div>
<div class="prop"><center><div class="k">Pre-load overview</div></center><div class="v">Keeps the overview built in the background so it opens instantly, at a small memory cost.</div></div>
</div>
<h2>Left Sidebar</h2>
<div class="props">
<div class="prop"><center><div class="k">AI</div></center><div class="v"><span class="tag">No</span> disables the assistant entirely. <span class="tag">Yes</span> turns it on, connecting to whichever provider you set up with your own API key. Google Gemini, Anthropic's Claude, and OpenAI's Codex can all be used in the left sidebar, each over its official API. Full plan (subscription) integration for each is coming later. <span class="tag">Local only</span> restricts it to a local Ollama model, so nothing leaves your machine.</div></div>
<div class="prop"><center><div class="k">Translator</div></center><div class="v">Click-to-translate selected text, powered by Gemini or a local LibreTranslate server.</div></div>
</div>
<p class="shot-note">The right sidebar and what it holds, then the lock screen settings below it.</p>
${shot('InterfaceConfig-2.webp','The right sidebar, its quick toggles and timer')}
<h2>Right Sidebar</h2>
<div class="props">
<div class="prop"><center><div class="k">Quick toggles</div></center><div class="v"><span class="tag">Classic</span> a horizontal row of pills. <span class="tag">Android</span> a 2-column grid like modern Android Quick Settings.</div></div>
<div class="prop"><center><div class="k">Columns</div></center><div class="v">How many columns when Android style is selected. Default 5.</div></div>
<div class="prop"><center><div class="k">Sliders</div></center><div class="v">Choose which quick sliders — Brightness, Volume, and Microphone — appear in the right sidebar. Toggle each on or off, or turn the whole set off.</div></div>
</div>
<h3>Timer & Pomodoro</h3>
<p>Built-in Pomodoro with customizable focus blocks, short and long breaks, and cycle counts. Alarms can be independently muted for Pomodoro and generic timers.</p>
<p class="shot-note">The lock screen, and the last two sections on the page: how long an on-screen display stays up, and which picker the wallpaper chooser uses.</p>
${shot('InterfaceConfig-3.webp','Lock screen, on-screen display and wallpaper selector')}
<h3>Lock screen</h3>
<div class="props">
<div class="prop"><center><div class="k">Automatic Lock</div></center><div class="v">Lock after <b>Delay</b> minutes of inactivity. Default 5.</div></div>
<div class="prop"><center><div class="k">Launch on startup</div></center><div class="v">Boot straight into the lock screen instead of the desktop.</div></div>
<div class="prop"><center><div class="k">Require password to power off / restart</div></center><div class="v">Blocks unauthorized shutdowns when the screen is locked.</div></div>
<div class="prop"><center><div class="k">Also unlock keyring</div></center><div class="v">Unlocking the screen also unlocks GNOME Keyring — no second password for Wi-Fi, Git creds, etc.</div></div>
<div class="prop"><center><div class="k">Use varying shapes for password characters</div></center><div class="v">Each password dot becomes a different subtle shape. Purely cosmetic.</div></div>
<div class="prop"><center><div class="k">Enable blur (Blurred style)</div></center><div class="v">Kawase blur behind the unlock prompt.</div></div>
</div>
<h2>On-screen display</h2>
<p>The little popup that appears when you press a brightness or volume key.</p>
<div class="props">
<div class="prop"><center><div class="k">Timeout (ms)</div></center><div class="v">How long the popup lingers after the last key press.</div></div>
</div>
<h2>Wallpaper selector</h2>
<p>Controls for the wallpaper picker itself — see <a href="#background">Background</a> for the wallpaper and its overlay widgets.</p>
`
};
// ---------- BACKGROUND ----------
PAGES.background = {
group: 'Settings', title: 'Background', icon: 'bg',
lede: 'How the wallpaper behaves, how one picture transitions to the next, and the eleven widgets that live on top of it.',
render: () => `
${shot('BackgroundConfig-1.webp','The Background settings page showing the wallpaper transition picker with its looping preview','Every transition, with a preview above the picker playing the one you have chosen.')}
<h2>Wallpaper transitions</h2>
<p>Changing the wallpaper does not have to be a hard cut. Pick how one picture transitions to the next and the preview above the picker plays your choice on a loop, so you can judge it before you commit.</p>
<div class="props">
<div class="prop"><center><div class="k">Crossfade</div></center><div class="v">The default. One picture dissolves into the next.</div></div>
<div class="prop"><center><div class="k">Slide</div></center><div class="v">The outgoing picture travels off while the new one follows it in.</div></div>
<div class="prop"><center><div class="k">Zoom</div></center><div class="v">The new wallpaper grows into place.</div></div>
<div class="prop"><center><div class="k">Wipe</div></center><div class="v">A hard edge sweeps across the screen.</div></div>
<div class="prop"><center><div class="k">Circle</div></center><div class="v">The new wallpaper opens out from the middle.</div></div>
<div class="prop"><center><div class="k">Ripple</div></center><div class="v">A wave crosses the screen and leaves the new picture behind it.</div></div>
<div class="prop"><center><div class="k">Peel</div></center><div class="v">The old wallpaper lifts away like a page.</div></div>
<div class="prop"><center><div class="k">Glitch</div></center><div class="v">A brief digital tear between the two.</div></div>
<div class="prop"><center><div class="k">CRT</div></center><div class="v">The old tube television collapse, then back out to the new picture.</div></div>
<div class="prop"><center><div class="k">Shatter</div></center><div class="v">The outgoing wallpaper breaks apart and falls.</div></div>
<div class="prop"><center><div class="k">Random</div></center><div class="v">A different one every time the wallpaper changes.</div></div>
<div class="prop"><center><div class="k">None</div></center><div class="v">Swap instantly, with no animation at all.</div></div>
</div>
<p>Transitions run on the graphics card. On older hardware, <b>Crossfade</b> and <b>None</b> are the cheapest of the set.</p>
<h2>Video wallpapers</h2>
<p>Pick a video the same way you pick a picture and it plays as your background — nothing to install first, and the colors are drawn from it just as they are from a still image. The picker shows your wallpapers as thumbnails, and a newly chosen one appears immediately while its palette is worked out in the background.</p>
${shot('BackgroundConfig-2.webp','Wallpaper panning, the frosted widget backgrounds switch, and the clock widget settings','Panning, the frosted backgrounds switch, and the start of the clock settings.')}
<h2>Wallpaper panning</h2>
<p>Controls how the wallpaper moves as you switch workspaces and toggle sidebars. The default feel is a gentle parallax that echoes the ripples in the mark.</p>
<div class="props">
<div class="prop"><center><div class="k">Vertical</div></center><div class="v">Pans up/down instead of left/right. Pair with a tall wallpaper if you use Scrolling layout.</div></div>
<div class="prop"><center><div class="k">Depends on workspace</div></center><div class="v">Pans as you change workspaces. On by default.</div></div>
<div class="prop"><center><div class="k">Depends on sidebars</div></center><div class="v">Slides the wallpaper when the left/right sidebars open, revealing more of it underneath.</div></div>
<div class="prop"><center><div class="k">Preferred wallpaper zoom (%)</div></center><div class="v">Baseline zoom level. 100% shows the image at screen size; >100% crops in and gives panning more room.</div></div>
</div>
<h2>Frosted glass</h2>
<p>Switch on <b>Frosted widget backgrounds</b> and every widget card blurs the wallpaper behind it instead of sitting on a flat color, with a slider for how soft the blur is.</p>
<p>It ships off. Each card that is on pays for its own blur, so a machine with older graphics is left alone unless you ask for it, and nothing is built at all while the switch is off.</p>
<h2>Widget: Clock</h2>
<p>The giant time readout is the signature of the default Mainstream wallpaper. Everything about it is adjustable — position, style, font, whether it shows the date, whether it's only visible when the screen is locked.</p>
<div class="props">
<div class="prop"><center><div class="k">Enable</div></center><div class="v">Master toggle.</div></div>
<div class="prop"><center><div class="k">Draggable / Least busy / Most busy</div></center><div class="v">Where the clock sits. <b>Least busy</b> auto-picks the emptiest corner; <b>Most busy</b> sits inside your window cluster as a deliberate hero element; <b>Draggable</b> lets you pin it by hand.</div></div>
<div class="prop"><center><div class="k">Show only when locked</div></center><div class="v">Clock hides when the desktop is active and reappears on the lock screen.</div></div>
<div class="prop"><center><div class="k">Clock style</div></center><div class="v"><span class="tag">Digital</span> numeric (default) <span class="tag">Cookie</span> analog pie-chart style <span class="tag">Pixel</span> a chunky pixel readout, upright or on its side. Lock-screen style is chosen separately.</div></div>
</div>
<h3>Digital clock settings</h3>
<div class="props">
<div class="prop"><center><div class="k">Vertical</div></center><div class="v">Stack hours over minutes for a portrait orientation.</div></div>
<div class="prop"><center><div class="k">Animate time change</div></center><div class="v">Numbers roll over each minute instead of snapping.</div></div>
<div class="prop"><center><div class="k">Show date</div></center><div class="v">The small date label under the clock.</div></div>
<div class="prop"><center><div class="k">Use adaptive alignment</div></center><div class="v">Left-aligns on the right side of the screen, right-aligns on the left. Keeps the readout from touching the edge.</div></div>
<div class="prop"><center><div class="k">Font family</div></center><div class="v">Default <b>Google Sans Flex</b>. Any fontconfig family with variable axes works.</div></div>
<div class="prop"><center><div class="k">Font weight / size / width / roundness</div></center><div class="v">Live sliders that drive Google Sans Flex\'s variable axes. Roundness is the signature axis — sliding it right gives you the default soft, open numerals.</div></div>
</div>
<h3>Cookie clock settings</h3>
<p>These appear when the clock style is set to <b>Cookie</b> — an analog clock drawn as a rounded, many-sided cookie shape.</p>
<div class="props">
<div class="prop"><center><div class="k">Auto styling with Gemini</div></center><div class="v">Lets Gemini look at your wallpaper and pick a matching cookie preset.<br/>Needs a Gemini API key (set in the left sidebar).</div></div>
<div class="prop"><center><div class="k">Sides</div></center><div class="v">How many corners the cookie has. Default 14.</div></div>
<div class="prop"><center><div class="k">Dial style</div></center><div class="v"><span class="tag">Numbers</span> (default) <span class="tag">Dots</span> <span class="tag">Full</span> or none at all.</div></div>
<div class="prop"><center><div class="k">Hour / Minute / Second hand</div></center><div class="v">Pick a style for each hand independently — or hide any of them.</div></div>
<div class="prop"><center><div class="k">Date style</div></center><div class="v">How the date renders inside the clock: bubble (default), border, rectangle, or hidden.</div></div>
<div class="prop"><center><div class="k">Hour marks / Digits in the middle</div></center><div class="v">Extra dial detail — each is offered with the dial styles it looks right on.</div></div>
<div class="prop"><center><div class="k">Use old sine wave cookie</div></center><div class="v">The earlier, softer cookie shape — more consistent at any side count, with less dramatic morphing.</div></div>
<div class="prop"><center><div class="k">Constantly rotate</div></center><div class="v">Keeps the cookie spinning at all times. Very heavy on the GPU — a fun demo, not a daily driver.</div></div>
</div>
<h3>Quote</h3>
<p>Enable it and a quote string appears beneath the clock. Useful for a personal mantra on the lock screen.</p>
<h2>Widget: Weather</h2>
<p>A compact weather card with icon, temperature, and forecast. Same data source as the bar\'s weather module. Positioning controls mirror the Clock widget — Draggable / Least busy / Most busy.</p>
${shot('BackgroundConfig-3.webp','The More widgets grid with a switch for each of the nine remaining widgets','The rest of the widgets sit in one grid, each with its own switch.')}
<h2>Widgets on the wallpaper</h2>
<p>Eleven widgets can sit on the desktop, each switched on and placed on its own. Drag one where you want it and it stays there, remembered as a share of the screen rather than a pixel position, so one theme lays your desktop out the same way on a laptop panel and a 4K monitor alike.</p>
<div class="props">
<div class="prop"><center><div class="k">Clock</div></center><div class="v">The big time readout. Three styles, covered below.</div></div>
<div class="prop"><center><div class="k">Weather</div></center><div class="v">Icon, temperature and forecast, from the same source as the bar.</div></div>
<div class="prop"><center><div class="k">Calendar</div></center><div class="v">The month at a glance, with today marked.</div></div>
<div class="prop"><center><div class="k">World clock</div></center><div class="v">Other time zones beside your own.</div></div>
<div class="prop"><center><div class="k">Notes</div></center><div class="v">Short notes kept on the desktop.</div></div>
<div class="prop"><center><div class="k">To do</div></center><div class="v">A checklist that lives on the wallpaper.</div></div>
<div class="prop"><center><div class="k">Timers</div></center><div class="v">Countdowns you can start and reset in place.</div></div>
<div class="prop"><center><div class="k">Resources</div></center><div class="v">Processor, memory and disk at a glance.</div></div>
<div class="prop"><center><div class="k">Media player</div></center><div class="v">What is playing, with controls.</div></div>
<div class="prop"><center><div class="k">Visualizer</div></center><div class="v">Audio drawn as it plays.</div></div>
<div class="prop"><center><div class="k">Picture</div></center><div class="v">Any image of your own, placed on the desktop.</div></div>
</div>
<h3>Where each widget sits</h3>
<div class="props">
<div class="prop"><center><div class="k">Draggable</div></center><div class="v">Put it exactly where you want by hand.</div></div>
<div class="prop"><center><div class="k">Least busy</div></center><div class="v">Finds the emptiest part of the wallpaper and sits there.</div></div>
<div class="prop"><center><div class="k">Most busy</div></center><div class="v">Sits inside the detail of the picture, as a deliberate hero element.</div></div>
<div class="prop"><center><div class="k">Lock widget positions</div></center><div class="v">Pins every widget where it stands, so a stray drag cannot move one.</div></div>
</div>
`
};
// ---------- DECORATIONS ----------
PAGES.decorations = {
group: 'Settings', title: 'Decorations', icon: 'sliders',
lede: 'How windows are drawn — their shape, transparency, blur, shadow and borders — plus the app style and icons your other programs use, the pointer, the fonts, and per-app window rules.',
render: () => `
<p class="shot-note">The top of the page: which decorations windows get, the title bar colors that follow from them, and the shape and transparency of the windows themselves.</p>
${shot('DecorationsConfig-1.webp','Window decorations, title bars, shape and transparency')}
<h2>Window decorations</h2>
<p>Six switches for how a window is drawn. Turning any of them off is a fair trade for speed on older hardware — the desktop keeps working exactly the same, it just draws less.</p>
<div class="props">
<div class="prop"><center><div class="k">Animations</div></center><div class="v">Window open and close effects, and the slide between workspaces. Turn off for the snappiest possible feel.</div></div>
<div class="prop"><center><div class="k">Blur</div></center><div class="v">Background blur behind transparent windows and panels. The most expensive thing on this page to draw.</div></div>
<div class="prop"><center><div class="k">Shadows</div></center><div class="v">Drop shadows underneath windows.</div></div>
<div class="prop"><center><div class="k">Borders</div></center><div class="v">Colored borders around active and inactive windows — useful for telling floating windows apart.</div></div>
<div class="prop"><center><div class="k">Rounded Corners</div></center><div class="v">Rounded corners on windows and the bar, following your theme radius.</div></div>
<div class="prop"><center><div class="k">Title Bars</div></center><div class="v">Show title bars on windows, so every window keeps its close and maximize buttons. Turning this on reveals a <b>Title bars</b> section below, for coloring them.</div></div>
</div>
${callout('note','A switch turns the section off', '<p>Each switch gates the matching section further down. With <strong>Blur</strong> off, the blur sliders stop having an effect — they keep their values for when you turn it back on.</p>')}
<h2>Title bars</h2>
<p>This section only appears while <b>Title Bars</b> above is on, since with them off there is no bar for a color to land on.</p>
<div class="props">
<div class="prop"><center><div class="k">Color</div></center><div class="v">Paints the title bar. Left empty, the title bar keeps the color it comes with, which is the one the plugin picks for itself. Applies as you edit.</div></div>
<div class="prop"><center><div class="k">Opacity</div></center><div class="v">How see-through the title bar is. It takes effect once a color is set: the opacity is folded into the color the plugin is handed, so on its own, with no color, there is nothing to make transparent.</div></div>
</div>
<h2>Window shape</h2>
<p>The geometry every window is laid out with.</p>
<div class="props">
<div class="prop"><center><div class="k">Corner roundness</div></center><div class="v">How round the corners are. All the way down is perfectly square.</div></div>
<div class="prop"><center><div class="k">Border thickness</div></center><div class="v">How heavy the outline around each window is.</div></div>
<div class="prop"><center><div class="k">Gap between windows</div></center><div class="v">The space tiled windows leave between each other.</div></div>
<div class="prop"><center><div class="k">Gap around the edge</div></center><div class="v">The margin between your windows and the edge of the screen.</div></div>
</div>
<h2>Window transparency</h2>
<p>How much of the wallpaper shows through a window, set separately for the one you are working in and the ones you are not.</p>
<div class="props">
<div class="prop"><center><div class="k">Focused window</div></center><div class="v">The window you are currently using.</div></div>
<div class="prop"><center><div class="k">Unfocused windows</div></center><div class="v">Everything behind it. Dropping this a little is an easy way to see at a glance which window has your keystrokes.</div></div>
</div>
<p class="shot-note">The effects drawn around and behind a window: its blur, the dimming of everything else, its border color and its shadow.</p>
${shot('DecorationsConfig-2.webp','Blur, dim, border color and shadow')}
<h2>Window blur</h2>
<p>What happens behind a transparent window. Needs <strong>Blur</strong> switched on above.</p>
<div class="props">
<div class="prop"><center><div class="k">Strength</div></center><div class="v">How far the blur reaches. Higher costs more to draw.</div></div>
<div class="prop"><center><div class="k">Noise</div></center><div class="v">A light grain over the blur, which stops large flat areas from banding.</div></div>
<div class="prop"><center><div class="k">Saturation</div></center><div class="v">How much color the blurred wallpaper keeps.</div></div>
<div class="prop"><center><div class="k">Blur through to the wallpaper</div></center><div class="v">Blur past the windows underneath and show the wallpaper instead, so a stack of windows does not muddy into itself.</div></div>
</div>
<h2>Window dim</h2>
<p>Darkens whatever you are not working in, which is the quietest way to keep your eye on the right window.</p>
<div class="props">
<div class="prop"><center><div class="k">Unfocused windows</div></center><div class="v">Whether the dimming happens at all.</div></div>
<div class="prop"><center><div class="k">Amount</div></center><div class="v">How dark they go. A little goes a long way.</div></div>
</div>
<h2>Window border color</h2>
<p>By default your borders are drawn from the wallpaper palette, so they change with your theme. Switch either one on to pick colors yourself instead — a gradient with as many stops as you like, at whatever angle.</p>
<div class="props">
<div class="prop"><center><div class="k">Active border</div></center><div class="v">The window you are using.</div></div>
<div class="prop"><center><div class="k">Inactive border</div></center><div class="v">Everything else.</div></div>
</div>
${callout('tip','Left alone, they follow your wallpaper', '<p>Leave both switched off and the borders keep tracking your theme, so a new wallpaper restyles them without you touching this page.</p>')}
<h2>Window shadow</h2>
<p>The shape of the shadow under each window. Needs <strong>Shadows</strong> switched on above.</p>
<div class="props">
<div class="prop"><center><div class="k">Size</div></center><div class="v">How far the shadow spreads.</div></div>
<div class="prop"><center><div class="k">Falloff</div></center><div class="v">How sharply it fades at the edge — low is a soft haze, high is a defined edge.</div></div>
<div class="prop"><center><div class="k">Darkness</div></center><div class="v">How dark it is.</div></div>
<div class="prop"><center><div class="k">Offset X / Offset Y</div></center><div class="v">Which direction it falls, as though you were moving the light source.</div></div>
</div>
<p class="shot-note">How windows move, the reset that undoes everything above, and the app style, icons and pointer the rest of the system uses.</p>
${shot('DecorationsConfig-3.webp','Animations, reset, system look and cursor')}
<h2>Window animations</h2>
<p>One list, holding a whole set of curves and timings.</p>
<div class="props">
<div class="prop"><center><div class="k">Style</div></center><div class="v"><span class="tag">Expressive</span> lively, with overshoot <span class="tag">Smooth</span> steady and unhurried <span class="tag">Minimal</span> short and plain, the cheapest to draw</div></div>
</div>
<h2>Reset</h2>
<p><strong>Reset window settings</strong> puts everything above back the way it shipped. It leaves the sections below alone — your app style, icons, pointer and fonts stay as you set them.</p>
<h2>System look</h2>
<p>The desktop follows your theme on its own. These three pick what everything <em>else</em> uses — your file manager, your browser, your text editor.</p>
<div class="props">
<div class="prop"><center><div class="k">App style</div></center><div class="v">The widget theme your programs are drawn with — buttons, menus, scrollbars.</div></div>
<div class="prop"><center><div class="k">Icons</div></center><div class="v">The icon set used across the desktop and inside apps.</div></div>
<div class="prop"><center><div class="k">Mouse cursor</div></center><div class="v">The pointer theme. Your choice survives a logout.</div></div>
</div>
${callout('tip','Saved with your themes', '<p>All three of these are captured when you save a theme, along with everything above, so switching themes brings the whole look with it — not just the colors.</p>')}
<h2>Cursor</h2>
<div class="props">
<div class="prop"><center><div class="k">Cursor Size</div></center><div class="v"><span class="tag">Small</span> 16px <span class="tag">Default</span> 24px <span class="tag">Large</span> 32px <span class="tag">Larger</span> 48px</div></div>
</div>
${callout('note','Not every cursor theme can be resized', '<p>The list only offers the sizes your chosen pointer theme can actually draw, so you will sometimes see fewer than four. A theme built at a single size stays that size whichever you pick.</p>')}
<p class="shot-note">The last two sections: the fonts everything is set in, and the per-window rules that override any of it for one app.</p>
${shot('DecorationsConfig-4.webp','Fonts and window rules')}
<h2>Fonts</h2>
<p>Mainstream uses <strong>Google Sans Flex</strong> and <strong>JetBrains Mono NF</strong> by default. Each list is searchable and shows every font in its own typeface, so you can read a name the way it will look.</p>
<div class="props">
<div class="prop"><center><div class="k">Main font</div></center><div class="v">The everyday interface font, used almost everywhere.</div></div>
<div class="prop"><center><div class="k">Numbers font</div></center><div class="v">Clocks, counters, and readouts, where even digit widths matter.</div></div>
<div class="prop"><center><div class="k">Title font</div></center><div class="v">Headings and larger titles.</div></div>
<div class="prop"><center><div class="k">Monospace font</div></center><div class="v">Terminal-style text and anything that needs to line up in columns.</div></div>
<div class="prop"><center><div class="k">Nerd font icons</div></center><div class="v">The glyph font behind the small icons in the bar and menus. Change this only for a font that carries the same glyphs.</div></div>
<div class="prop"><center><div class="k">Reading font</div></center><div class="v">Longer passages of text, like notification bodies and the AI assistant.</div></div>
<div class="prop"><center><div class="k">Expressive font</div></center><div class="v">The occasional display font used for emphasis.</div></div>
</div>
${callout('info','Your apps follow along', '<p>Setting the main font here also hands it to your programs, so your browser and file manager match the desktop instead of drifting from it.</p>')}
<h2>Window rules</h2>
<p>Everything above applies to every window at once. A rule is for when one app should be treated differently — a calculator that should always float, a video player that should never dim, a chat window that belongs on its own workspace.</p>
<p>Press <strong>Add rule</strong> and name the app you mean, either by picking it from the windows you have open or by typing what it matches. Then choose what should happen to it: where it opens, how see-through it is, whether it gets a border, a shadow, blur, or an animation at all.</p>
<div class="props">
<div class="prop"><center><div class="k">Match</div></center><div class="v">Which windows the rule is about — by app, by title, or both.</div></div>
<div class="prop"><center><div class="k">Effects</div></center><div class="v">What changes for them: floating, size and position, workspace, opacity, blur, shadow, border, rounding, dimming, and more.</div></div>
<div class="prop"><center><div class="k">Order</div></center><div class="v">Rules apply top to bottom, so when two disagree the later one wins. Use the arrows to reorder.</div></div>
</div>
${callout('tip','Rules travel with a theme', '<p>Your rules are saved into a theme along with everything else on this page, so sharing a theme shares the behaviour you built up — not just how it looks.</p>')}
${callout('note','Written to a file of its own', '<p>Rules are kept separately from anything you write by hand, so the settings page never overwrites your own Hyprland configuration.</p>')}
`
};
// ---------- THEMES ----------
PAGES.themes = {
group: 'Settings', title: 'Themes', icon: 'themes',
lede: 'A theme is a snapshot of your entire look — wallpaper, colors, UI tweaks, decorations. Save as many as you want and switch between them instantly.',
render: () => `
${shot('ThemesConfig.webp','Themes page')}
<h2>What a theme captures</h2>
<p>A theme is a full snapshot of your desktop as it stands — not just the wallpaper and colors. Switching themes switches all of this at once:</p>
<div class="props">
<div class="prop"><center><div class="k">Wallpaper</div></center><div class="v">The image file itself is copied into the theme, so the theme keeps working even if you later move or delete the original.</div></div>
<div class="prop"><center><div class="k">Colors</div></center><div class="v">Your <strong>Material You palette style</strong> (Expressive, Monochrome, …) and <strong>Light/Dark</strong> choice. On apply, the palette is regenerated from the theme\'s wallpaper — and it reaches further than the desktop: your apps follow the light/dark switch and the terminal recolors too.</div></div>
<div class="prop"><center><div class="k">Every Settings option</div></center><div class="v">The desktop configuration as it stood when you saved: <strong>bar</strong> position, style, and modules; the <strong>dock</strong>’s size, marks and end buttons; <strong>background widgets</strong> (clock, weather, quote); <strong>fonts</strong> and sizes; <strong>transparency</strong>; interface and launcher tweaks.</div></div>
<div class="prop"><center><div class="k">Window decorations</div></center><div class="v">Animations, blur, shadows, borders and gaps, rounded corners, and title bars — applied live, so windows re-dress the moment you switch.</div></div>
<div class="prop"><center><div class="k">System look</div></center><div class="v">Your app style, icon set, and mouse pointer, so your other programs change with the desktop instead of staying behind. Set these on the <a href="#decorations">Decorations</a> page.</div></div>
<div class="prop"><center><div class="k">Preview</div></center><div class="v">A screenshot taken at save time becomes the theme\'s thumbnail in the grid.</div></div>
</div>
${callout('note','Two things a theme leaves alone', '<p>Your <b>pinned dock apps</b> and your <b>weather settings</b> stay with the machine. Pins are stripped when a theme is saved and taken from your live config whenever one is applied, so switching looks never rearranges your dock and an imported theme cannot leave you with launchers for software you do not have. Weather is left alone the same way, so applying somebody else’s theme will not move your forecast to their city or flip your degrees.</p>')}
<h2>Renaming and reapplying</h2>
<p>Right-click any saved theme tile for a small menu on the card. <strong>Rename</strong> turns the name into an editable field in place: Enter or a click away commits it, Escape cancels. Only the display name changes, so the theme’s folder on disk and any Day/Night pairing pointing at it keep working.</p>
<p><strong>Reapply</strong> shows only on the theme currently applied, and puts that look back after your settings have drifted from it. It is there because the main button on the active card reads <b>Update</b>, which overwrites the theme with your current settings rather than the other way round.</p>
<h2>Saving your first theme</h2>
<ol>
<li>Dial in your look — wallpaper, palette style, font, and any other interface settings you care to change.</li>
<li>Hit <strong>Save current as theme</strong>.</li>
<li>Name it. Themes appear as thumbnails in the page you can click to switch instantly.</li>
</ol>
<h2>Switching</h2>
<p>Click any saved theme tile to apply it — the whole desktop re-skins in under a second with a soft crossfade. <strong>Update</strong> on the active theme overwrites it with whatever you\'ve tweaked since.</p>
<figure>
<div class="shot">
<video src="assets/docs/ThemesConfig-theme-switching-example-video.mp4" autoplay loop muted playsinline controls style="width:100%;display:block"></video>
</div>
<figcaption>Switching live: one click and the wallpaper, colors, bar, dock, and widgets all follow in a single motion.</figcaption>
</figure>
<h2>Day/Night Themes</h2>
${shot('ThemesConfig-DayNight.webp','Day/Night Themes section of the Themes page','Pair two saved themes to time of day — a bright one for daytime, a dark one for night — and Mainstream switches between them on its own.')}
<p>Pick a <strong>Day</strong> theme and a <strong>Night</strong> theme from your saved collection, then choose how the switch happens:</p>
<div class="props">
<div class="prop"><center><div class="k">Follow Night Light</div></center><div class="v">Switches together with the Night Light schedule: day theme at sunrise, night theme at sunset. Offered whether or not the Night Light color filter itself is switched on, since you may want the themes to follow the sun without the screen being warmed. A line under the dropdown spells out the hours it will actually cover, because those hours belong to Night Light and are edited over on the <a href="#display">Display</a> page rather than here. At polar latitudes it says so instead of naming a time.</div></div>
<div class="prop"><center><div class="k">Custom times</div></center><div class="v">Set your own day-start and night-start times if you\'d rather not follow the sun.</div></div>
<div class="prop"><center><div class="k">Off</div></center><div class="v">No automatic switching — the desktop keeps whichever theme you applied last.</div></div>
</div>
${callout('tip','Two workflows, one OS', '<p>Build a "Focus" theme with muted grays, no blur, minimal chrome; and a "Weekend" theme with a photo wallpaper, expressive colors, and the clock widget enabled. Switch with one click depending on what you\'re doing — or let Day/Night switch for you.</p>')}
<h2>Sharing themes</h2>
<p>A theme travels as a single <code>.mtheme</code> file — the settings snapshot, the decoration flags, the wallpaper, and the preview thumbnail, packed together. <strong>Export</strong> writes one out, <strong>Import</strong> reads one in. Nothing needs to be zipped or copied by hand.</p>
<div class="props">
<div class="prop"><center><div class="k">Export</div></center><div class="v">Saves the selected theme as a <code>.mtheme</code> file wherever you choose. Machine-specific details are stripped on the way out, so the file makes sense on somebody else\'s computer.</div></div>
<div class="prop"><center><div class="k">Import</div></center><div class="v">Opens a <code>.mtheme</code> file and adds it to your collection. If you already have a theme of the same name, the imported one replaces it — so re-importing an updated copy does the right thing rather than leaving you with duplicates.</div></div>
</div>
${callout('note','If a theme needs something you don\'t have', '<p>A theme can name an app style, icon set, or pointer theme that isn\'t installed on your machine. It still imports, and Mainstream tells you which piece is missing so you can install it and import the file again for the complete look. That notice stays up until you\'ve dealt with it.</p>')}
<p>Themes still live as plain folders under <code>~/.config/mainstream/themes/</code> if you\'d rather poke at them directly.</p>
`
};
// ---------- DISPLAY ----------
PAGES.display = {
group: 'Settings', title: 'Display', icon: 'display',
lede: 'Arrange monitors, pick resolutions and refresh rates, enable VRR and 10-bit color, and dial in color management per monitor — including HDR.',
render: () => `
${shot('DisplayConfig-1.webp','Display arrangement and primary monitor settings')}
<h2>Display Arrangement</h2>
<p>The top card draws your monitors to scale, so a 3840×2160 panel visually dwarfs a 1920×1080 one. <strong>Drag a monitor to where you want it</strong> and drop it: Mainstream picks the <em>Position</em> for whichever side of the default display you left it on and works out the offset needed to land it exactly there, keeping the dropdown and the offset boxes below in step with the picture. The default display stays at the origin and cannot be dragged, since everything else is placed relative to it.</p>
<p>If you would rather be precise than drag, the <strong>Position</strong> dropdown under each monitor still takes <em>To Right of Default Display</em>, <em>Below Default Display</em> and the rest, and the two offsets below it nudge from there.</p>
<div class="props">
<div class="prop"><center><div class="k">Horizontal Offset</div></center><div class="v">Nudges the monitor left or right in pixels, on top of the Position it has been given. This is what lines up displays of different physical size at the bezel instead of leaving them flush at one edge. The small reset button at the end of the row snaps it back to zero.</div></div>
<div class="prop"><center><div class="k">Vertical Offset</div></center><div class="v">The same, up and down.</div></div>
</div>
${callout('note','Offsets cannot overlap the default display', '<p>Each offset is capped by the Position it belongs to, so a monitor set to the right of the default display can only be nudged further right, never back across it. With no Position chosen, both offsets sit at zero and stay there.</p>')}
<h2>Per-monitor settings</h2>
<div class="props">
<div class="prop"><center><div class="k">Enabled</div></center><div class="v">Disable a monitor without unplugging it. The home icon on the right pins it as the <b>Default</b> (primary) display.</div></div>
<div class="prop"><center><div class="k">Mode</div></center><div class="v">Resolution × refresh rate, picked from the modes your monitor advertises.</div></div>
<div class="prop"><center><div class="k">Scale</div></center><div class="v">UI scale. The menu shows only the steps that render pixel-perfectly on that monitor — up to ten of them between 100% and 200% — so whichever you pick stays sharp.</div></div>
<div class="prop"><center><div class="k">Orientation</div></center><div class="v">Landscape / Portrait / Landscape (Flipped) / Portrait (Flipped).</div></div>
<div class="prop"><center><div class="k">VRR</div></center><div class="v">Variable Refresh Rate. <b>Always On</b> for G-Sync, FreeSync, and Adaptive-Sync monitors — smoother gaming. <b>Fullscreen Only</b> saves power on the desktop. Grays out if your display or driver can\'t do it.</div></div>