replicas-computer 0.2.9 → 0.2.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -8,6 +8,7 @@ The versioned computer-use runtime for Replicas workspace images.
8
8
  - `src/stream-viewer.ts` owns browser decoding, audio playback, reconnects, and interactive input.
9
9
  - `src/viewer.ts` owns the optional noVNC fallback.
10
10
  - `assets/desktop/start-services.sh` owns the X11 and stream process lifecycle.
11
+ - `assets/desktop/` owns the desktop theme: `brand-wallpaper.svg` (regenerate with `bun scripts/render-wallpaper.ts`), `tint2rc` dock, `openbox-theme/`, `gtk-settings.ini`, the `replicas-terminal` wrapper, `themes/` palettes that `start-services.sh` renders into those templates (`--theme light|dark` switches a running desktop), and the bundled fonts (static TTF instances of General Sans and Geist Mono; variable and WOFF2 builds render with wrong metrics in Pango and VTE).
11
12
 
12
13
  The viewer and agent command paths are independent. One on-demand encoder is shared by all viewers, stops when the last viewer disconnects, and restarts without reloading the page. The default 1920×1080 stream uses low-latency H.264 and Opus; noVNC remains available as an opt-in fallback.
13
14
 
@@ -0,0 +1,16 @@
1
+ <svg width="1920" height="1080" viewBox="0 0 1920 1080" xmlns="http://www.w3.org/2000/svg">
2
+ <defs>
3
+ <linearGradient id="cell" x1="0" y1="0" x2="1" y2="1"><stop stop-color="#2fc487" stop-opacity="0.3"/><stop offset="1" stop-color="#2fc487" stop-opacity="0.14"/></linearGradient>
4
+ <radialGradient id="glow" gradientUnits="userSpaceOnUse" cx="960" cy="476" r="620"><stop stop-color="#2fc487" stop-opacity="0.1"/><stop offset="1" stop-color="#2fc487" stop-opacity="0"/></radialGradient>
5
+ <pattern id="grid" width="64" height="64" y="28" patternUnits="userSpaceOnUse"><path d="M0.5 0V64M0 0.5H64" stroke="#162118" stroke-opacity="0.1"/></pattern>
6
+ <filter id="cell-glow" x="-25%" y="-25%" width="150%" height="150%"><feDropShadow dx="0" dy="0" stdDeviation="10" flood-color="#2fc487" flood-opacity="0.18"/></filter>
7
+ </defs>
8
+ <rect width="1920" height="1080" fill="#f4f5f1"/>
9
+ <rect width="1920" height="1080" fill="url(#glow)"/>
10
+ <rect width="1920" height="1080" fill="url(#grid)"/>
11
+ <g fill="url(#cell)" stroke="#2fc487" filter="url(#cell-glow)"><rect x="768.5" y="220.5" width="64" height="64"/><rect x="768.5" y="284.5" width="64" height="64"/><rect x="832.5" y="220.5" width="64" height="64"/><rect x="832.5" y="284.5" width="64" height="64"/><rect x="896.5" y="220.5" width="64" height="64"/><rect x="896.5" y="284.5" width="64" height="64"/><rect x="960.5" y="220.5" width="64" height="64"/><rect x="960.5" y="284.5" width="64" height="64"/><rect x="1024.5" y="348.5" width="64" height="64"/><rect x="1024.5" y="412.5" width="64" height="64"/><rect x="1088.5" y="348.5" width="64" height="64"/><rect x="1088.5" y="412.5" width="64" height="64"/><rect x="768.5" y="476.5" width="64" height="64"/><rect x="768.5" y="540.5" width="64" height="64"/><rect x="832.5" y="476.5" width="64" height="64"/><rect x="832.5" y="540.5" width="64" height="64"/><rect x="896.5" y="476.5" width="64" height="64"/><rect x="896.5" y="540.5" width="64" height="64"/><rect x="960.5" y="476.5" width="64" height="64"/><rect x="960.5" y="540.5" width="64" height="64"/><rect x="768.5" y="604.5" width="64" height="64"/><rect x="768.5" y="668.5" width="64" height="64"/><rect x="832.5" y="604.5" width="64" height="64"/><rect x="832.5" y="668.5" width="64" height="64"/><rect x="1024.5" y="604.5" width="64" height="64"/><rect x="1024.5" y="668.5" width="64" height="64"/><rect x="1088.5" y="604.5" width="64" height="64"/><rect x="1088.5" y="668.5" width="64" height="64"/><rect x="320.5" y="156.5" width="64" height="64"/><rect x="384.5" y="220.5" width="64" height="64"/><rect x="256.5" y="284.5" width="64" height="64"/><rect x="320.5" y="284.5" width="64" height="64"/><rect x="384.5" y="284.5" width="64" height="64"/><rect x="1536.5" y="220.5" width="64" height="64"/><rect x="1472.5" y="284.5" width="64" height="64"/><rect x="1600.5" y="348.5" width="64" height="64"/><rect x="1536.5" y="348.5" width="64" height="64"/><rect x="1472.5" y="348.5" width="64" height="64"/><rect x="448.5" y="860.5" width="64" height="64"/><rect x="512.5" y="796.5" width="64" height="64"/><rect x="384.5" y="732.5" width="64" height="64"/><rect x="448.5" y="732.5" width="64" height="64"/><rect x="512.5" y="732.5" width="64" height="64"/><rect x="1344.5" y="796.5" width="64" height="64"/><rect x="1408.5" y="796.5" width="64" height="64"/><rect x="1472.5" y="796.5" width="64" height="64"/><rect x="1664.5" y="540.5" width="64" height="64"/><rect x="1728.5" y="540.5" width="64" height="64"/><rect x="1664.5" y="604.5" width="64" height="64"/><rect x="1728.5" y="604.5" width="64" height="64"/></g>
12
+ <g font-family="Geist Mono, monospace" font-size="5" font-weight="600" fill="#2f9d57"><text x="774" y="233">AGENT-73</text><text x="774" y="276">CODING</text><text x="774" y="297">AGENT-45</text><text x="774" y="340">DEPLOYING</text><text x="838" y="233">AGENT-10</text><text x="838" y="276">LINTING</text><text x="838" y="297">AGENT-82</text><text x="838" y="340">MERGING</text><text x="902" y="233">AGENT-47</text><text x="902" y="276">REFACTORING</text><text x="902" y="297">AGENT-19</text><text x="902" y="340">CODING</text><text x="966" y="233">AGENT-84</text><text x="966" y="276">RUNNING TESTS</text><text x="966" y="297">AGENT-56</text><text x="966" y="340">LINTING</text><text x="1030" y="361">AGENT-65</text><text x="1030" y="404">CODING</text><text x="1030" y="425">AGENT-37</text><text x="1030" y="468">DEPLOYING</text><text x="1094" y="361">AGENT-02</text><text x="1094" y="404">LINTING</text><text x="1094" y="425">AGENT-74</text><text x="1094" y="468">MERGING</text><text x="774" y="489">AGENT-61</text><text x="774" y="532">DEPLOYING</text><text x="774" y="553">AGENT-33</text><text x="774" y="596">REFACTORING</text><text x="838" y="489">AGENT-98</text><text x="838" y="532">MERGING</text><text x="838" y="553">AGENT-70</text><text x="838" y="596">RUNNING TESTS</text><text x="902" y="489">AGENT-35</text><text x="902" y="532">CODING</text><text x="902" y="553">AGENT-07</text><text x="902" y="596">DEPLOYING</text><text x="966" y="489">AGENT-72</text><text x="966" y="532">LINTING</text><text x="966" y="553">AGENT-44</text><text x="966" y="596">MERGING</text><text x="774" y="617">AGENT-05</text><text x="774" y="660">CODING</text><text x="774" y="681">AGENT-77</text><text x="774" y="724">DEPLOYING</text><text x="838" y="617">AGENT-42</text><text x="838" y="660">LINTING</text><text x="838" y="681">AGENT-14</text><text x="838" y="724">MERGING</text><text x="1030" y="617">AGENT-53</text><text x="1030" y="660">DEPLOYING</text><text x="1030" y="681">AGENT-25</text><text x="1030" y="724">REFACTORING</text><text x="1094" y="617">AGENT-90</text><text x="1094" y="660">MERGING</text><text x="1094" y="681">AGENT-62</text><text x="1094" y="724">RUNNING TESTS</text><text x="326" y="169">AGENT-42</text><text x="326" y="212">LINTING</text><text x="390" y="233">AGENT-51</text><text x="390" y="276">CODING</text><text x="262" y="297">AGENT-49</text><text x="262" y="340">REFACTORING</text><text x="326" y="297">AGENT-86</text><text x="326" y="340">RUNNING TESTS</text><text x="390" y="297">AGENT-23</text><text x="390" y="340">DEPLOYING</text><text x="1542" y="233">AGENT-17</text><text x="1542" y="276">CODING</text><text x="1478" y="297">AGENT-52</text><text x="1478" y="340">RUNNING TESTS</text><text x="1606" y="361">AGENT-98</text><text x="1606" y="404">RUNNING TESTS</text><text x="1542" y="361">AGENT-61</text><text x="1542" y="404">REFACTORING</text><text x="1478" y="361">AGENT-24</text><text x="1478" y="404">LINTING</text><text x="454" y="873">AGENT-08</text><text x="454" y="916">MERGING</text><text x="518" y="809">AGENT-73</text><text x="518" y="852">REFACTORING</text><text x="390" y="745">AGENT-27</text><text x="390" y="788">REFACTORING</text><text x="454" y="745">AGENT-64</text><text x="454" y="788">RUNNING TESTS</text><text x="518" y="745">AGENT-01</text><text x="518" y="788">DEPLOYING</text><text x="1350" y="809">AGENT-54</text><text x="1350" y="852">RUNNING TESTS</text><text x="1414" y="809">AGENT-91</text><text x="1414" y="852">DEPLOYING</text><text x="1478" y="809">AGENT-28</text><text x="1478" y="852">MERGING</text><text x="1670" y="553">AGENT-51</text><text x="1670" y="596">DEPLOYING</text><text x="1734" y="553">AGENT-88</text><text x="1734" y="596">MERGING</text><text x="1670" y="617">AGENT-23</text><text x="1670" y="660">REFACTORING</text><text x="1734" y="617">AGENT-60</text><text x="1734" y="660">RUNNING TESTS</text></g>
13
+ <path transform="translate(893.05 842)" fill="#162118" fill-opacity="0.9" d="M5.3 0H3.3V-28.7H13.2Q17.5 -28.7 20 -26.5Q22.6 -24.3 22.6 -20.2Q22.6 -16.9 20.5 -14.6Q18.4 -12.4 14.9 -12L23.3 0H20.9L12.8 -11.8H5.3ZM5.3 -27.1V-13.4H13Q16.5 -13.4 18.5 -15.2Q20.6 -17 20.6 -20.2Q20.6 -23.5 18.5 -25.3Q16.5 -27.1 13 -27.1Z M33.8 0.4Q31 0.4 28.8 -0.9Q26.6 -2.3 25.4 -4.9Q24.2 -7.4 24.2 -10.7Q24.2 -13.7 25.5 -16.2Q26.7 -18.6 28.8 -20Q30.9 -21.4 33.6 -21.4Q35.8 -21.4 37.5 -20.6Q39.2 -19.7 40.5 -18.2Q41.7 -16.7 42.3 -14.7Q42.9 -12.6 42.8 -10.1H25.2V-11.5H40.9Q40.7 -15.4 38.8 -17.7Q36.8 -19.9 33.6 -19.9Q31.4 -19.9 29.7 -18.7Q28 -17.6 27 -15.5Q26.1 -13.5 26.1 -10.7Q26.1 -7.8 27 -5.6Q27.9 -3.4 29.7 -2.3Q31.4 -1.1 33.8 -1.1Q36.7 -1.1 38.6 -2.7Q40.6 -4.3 41.1 -7.1H42.9Q42.3 -3.6 39.8 -1.6Q37.4 0.4 33.8 0.4Z M64.2 -10.5Q64.2 -7.2 63.1 -4.8Q61.9 -2.3 59.9 -1Q57.8 0.4 55 0.4Q52.5 0.4 50.5 -1Q48.5 -2.4 47.4 -4.8V7.7H45.5V-21H47.3V-15.9Q48.3 -18.5 50.4 -19.9Q52.5 -21.4 55 -21.4Q57.8 -21.4 59.9 -20Q61.9 -18.7 63.1 -16.2Q64.2 -13.8 64.2 -10.5ZM62.3 -10.5Q62.3 -14.8 60.3 -17.3Q58.3 -19.8 54.8 -19.8Q52.7 -19.8 51 -18.7Q49.3 -17.6 48.3 -15.5Q47.3 -13.5 47.3 -10.5Q47.3 -7.7 48.3 -5.6Q49.2 -3.5 50.9 -2.3Q52.6 -1.2 54.8 -1.2Q58.3 -1.2 60.3 -3.6Q62.3 -6.1 62.3 -10.5Z M68.7 0H66.8V-28.7H68.7Z M74.8 0H72.9V-21H74.8ZM75.6 -25.8Q75.6 -25.1 75.2 -24.6Q74.7 -24.1 73.9 -24.1Q73.1 -24.1 72.6 -24.6Q72.1 -25.1 72.1 -25.8Q72.1 -26.6 72.6 -27Q73.1 -27.5 73.9 -27.5Q74.7 -27.5 75.2 -27Q75.6 -26.6 75.6 -25.8Z M86.5 0.4Q83.8 0.4 81.8 -0.9Q79.7 -2.3 78.6 -4.8Q77.4 -7.3 77.4 -10.5Q77.4 -13.7 78.6 -16.2Q79.7 -18.6 81.8 -20Q83.9 -21.4 86.5 -21.4Q88.9 -21.4 90.7 -20.4Q92.6 -19.4 93.8 -17.6Q95 -15.7 95.5 -13.2H93.6Q93 -16.3 91.2 -18.1Q89.3 -19.8 86.5 -19.8Q84.4 -19.8 82.8 -18.6Q81.1 -17.4 80.2 -15.4Q79.3 -13.3 79.3 -10.5Q79.3 -7.7 80.2 -5.6Q81.1 -3.5 82.8 -2.3Q84.4 -1.1 86.5 -1.1Q89.3 -1.1 91.2 -2.9Q93.1 -4.7 93.6 -7.8H95.5Q95.1 -5.2 93.8 -3.4Q92.6 -1.6 90.8 -0.6Q88.9 0.4 86.5 0.4Z M111.1 0V-4.2Q110.3 -2.1 108.3 -0.9Q106.4 0.4 103.9 0.4Q100.6 0.4 98.7 -1.3Q96.7 -2.9 96.7 -5.7Q96.7 -8.8 99.2 -10.4Q101.6 -11.9 106.4 -11.9Q107.4 -11.9 108.3 -11.9Q109.3 -11.8 111 -11.7V-13.6Q111 -16.6 109.5 -18.2Q108.1 -19.9 105.4 -19.9Q102.6 -19.9 100.9 -18.2Q99.3 -16.5 99.2 -13.7H97.5Q97.5 -16 98.5 -17.7Q99.5 -19.4 101.3 -20.4Q103.1 -21.4 105.4 -21.4Q108.9 -21.4 110.9 -19.4Q112.8 -17.4 112.8 -13.8V0ZM98.6 -5.8Q98.6 -3.7 100.1 -2.4Q101.6 -1 104 -1Q107.2 -1 109.1 -3.1Q111 -5.1 111 -8.4V-10.4Q109.5 -10.5 108.5 -10.5Q107.4 -10.6 106.5 -10.6Q102.5 -10.6 100.5 -9.4Q98.6 -8.2 98.6 -5.8Z M131.9 -5.5Q131.9 -2.8 129.8 -1.2Q127.7 0.4 123.9 0.4Q120.3 0.4 118 -1.4Q115.8 -3.2 115.5 -6.4H117.3Q117.4 -3.9 119.2 -2.5Q121 -1.1 124 -1.1Q126.9 -1.1 128.5 -2.2Q130 -3.3 130 -5.3Q130 -7.1 128.9 -8Q127.8 -8.9 125.2 -9.4L122.4 -10Q119.3 -10.6 117.8 -12Q116.3 -13.4 116.3 -15.6Q116.3 -17.3 117.2 -18.6Q118.2 -19.9 119.8 -20.6Q121.5 -21.4 123.7 -21.4Q126 -21.4 127.7 -20.6Q129.5 -19.8 130.5 -18.3Q131.5 -16.8 131.7 -14.8H129.9Q129.7 -17.2 128 -18.6Q126.4 -19.9 123.7 -19.9Q121.2 -19.9 119.6 -18.8Q118.1 -17.7 118.1 -15.8Q118.1 -14 119.2 -13.1Q120.4 -12.1 123 -11.6L125.9 -11Q129 -10.4 130.5 -9.1Q131.9 -7.8 131.9 -5.5Z"/>
14
+ <g font-family="Geist Mono, monospace" font-size="14" fill="#162118" fill-opacity="0.4" text-anchor="middle"><text x="14" y="22">+</text><text x="1906" y="22">+</text><text x="14" y="1070">+</text><text x="1906" y="1070">+</text></g>
15
+ <text x="34" y="22" font-family="Geist Mono, monospace" font-size="10" letter-spacing="1.4" fill="#162118" fill-opacity="0.45">REPLICAS / DESKTOP</text>
16
+ </svg>
@@ -1,54 +1,16 @@
1
- <svg width="1920" height="1080" viewBox="0 0 910 1010" preserveAspectRatio="none" fill="none" xmlns="http://www.w3.org/2000/svg">
2
- <g clip-path="url(#clip0_brand_wallpaper)">
3
- <g clip-path="url(#clip1_brand_wallpaper)">
4
- <g filter="url(#filter0_n_brand_wallpaper)">
5
- <path d="M905 5H5V1005H905V5Z" fill="url(#paint0_linear_brand_wallpaper)"/>
6
- </g>
7
- <g filter="url(#filter1_f_brand_wallpaper)">
8
- <path d="M-2.98651 642.026C-2.98651 642.026 -141.133 716.811 -223.859 615.965C-306.584 515.119 -212.815 254.222 -157.739 166.382C-102.663 78.5416 289.934 113.449 372.659 214.295C455.385 315.141 -2.98651 642.026 -2.98651 642.026Z" fill="#082C25" fill-opacity="0.75"/>
9
- </g>
10
- <g filter="url(#filter2_f_brand_wallpaper)">
11
- <path d="M835.074 696.861C835.074 696.861 907.89 736.28 951.494 683.124C995.099 629.969 945.674 492.451 916.643 446.151C887.613 399.851 680.677 418.25 637.072 471.405C593.468 524.561 835.074 696.861 835.074 696.861Z" fill="#082C25" fill-opacity="0.7"/>
12
- </g>
13
- </g>
14
- </g>
1
+ <svg width="1920" height="1080" viewBox="0 0 1920 1080" xmlns="http://www.w3.org/2000/svg">
15
2
  <defs>
16
- <filter id="filter0_n_brand_wallpaper" x="5" y="5" width="900" height="1000" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
17
- <feFlood flood-opacity="0" result="BackgroundImageFix"/>
18
- <feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
19
- <feTurbulence type="fractalNoise" baseFrequency="1.0779999494552612 1.0779999494552612" stitchTiles="stitch" numOctaves="3" result="noise" seed="4356" />
20
- <feColorMatrix in="noise" type="luminanceToAlpha" result="alphaNoise" />
21
- <feComponentTransfer in="alphaNoise" result="coloredNoise1">
22
- <feFuncA type="discrete" tableValues="1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 "/>
23
- </feComponentTransfer>
24
- <feComposite operator="in" in2="shape" in="coloredNoise1" result="noise1Clipped" />
25
- <feFlood flood-color="rgba(0, 0, 0, 0.2)" result="color1Flood" />
26
- <feComposite operator="in" in2="noise1Clipped" in="color1Flood" result="color1" />
27
- <feMerge result="effect1_noise_brand_wallpaper">
28
- <feMergeNode in="shape" />
29
- <feMergeNode in="color1" />
30
- </feMerge>
31
- </filter>
32
- <filter id="filter1_f_brand_wallpaper" x="-496.13" y="-123.322" width="1118.34" height="1031.59" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
33
- <feFlood flood-opacity="0" result="BackgroundImageFix"/>
34
- <feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
35
- <feGaussianBlur stdDeviation="119.783" result="effect1_foregroundBlur_brand_wallpaper"/>
36
- </filter>
37
- <filter id="filter2_f_brand_wallpaper" x="505.533" y="293.449" width="589.474" height="543.749" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
38
- <feFlood flood-opacity="0" result="BackgroundImageFix"/>
39
- <feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
40
- <feGaussianBlur stdDeviation="63.1371" result="effect1_foregroundBlur_brand_wallpaper"/>
41
- </filter>
42
- <linearGradient id="paint0_linear_brand_wallpaper" x1="-5.01855" y1="5" x2="999.36" y2="898.989" gradientUnits="userSpaceOnUse">
43
- <stop stop-color="#1B9179"/>
44
- <stop offset="0.128829" stop-color="#1D8570"/>
45
- <stop offset="1" stop-color="#082B24"/>
46
- </linearGradient>
47
- <clipPath id="clip0_brand_wallpaper">
48
- <rect x="5" y="5" width="900" height="1000" fill="white"/>
49
- </clipPath>
50
- <clipPath id="clip1_brand_wallpaper">
51
- <rect width="900" height="1000" fill="white" transform="translate(5 5)"/>
52
- </clipPath>
3
+ <linearGradient id="cell" x1="0" y1="0" x2="1" y2="1"><stop stop-color="#082b24" stop-opacity="0.95"/><stop offset="1" stop-color="#005b45" stop-opacity="0.82"/></linearGradient>
4
+ <radialGradient id="glow" gradientUnits="userSpaceOnUse" cx="960" cy="476" r="620"><stop stop-color="#3eeba3" stop-opacity="0.07"/><stop offset="1" stop-color="#3eeba3" stop-opacity="0"/></radialGradient>
5
+ <pattern id="grid" width="64" height="64" y="28" patternUnits="userSpaceOnUse"><path d="M0.5 0V64M0 0.5H64" stroke="#ffffff" stroke-opacity="0.12"/></pattern>
6
+ <filter id="cell-glow" x="-25%" y="-25%" width="150%" height="150%"><feDropShadow dx="0" dy="0" stdDeviation="10" flood-color="#3eeba3" flood-opacity="0.16"/></filter>
53
7
  </defs>
8
+ <rect width="1920" height="1080" fill="#121212"/>
9
+ <rect width="1920" height="1080" fill="url(#glow)"/>
10
+ <rect width="1920" height="1080" fill="url(#grid)"/>
11
+ <g fill="url(#cell)" stroke="#3eeba3" filter="url(#cell-glow)"><rect x="768.5" y="220.5" width="64" height="64"/><rect x="768.5" y="284.5" width="64" height="64"/><rect x="832.5" y="220.5" width="64" height="64"/><rect x="832.5" y="284.5" width="64" height="64"/><rect x="896.5" y="220.5" width="64" height="64"/><rect x="896.5" y="284.5" width="64" height="64"/><rect x="960.5" y="220.5" width="64" height="64"/><rect x="960.5" y="284.5" width="64" height="64"/><rect x="1024.5" y="348.5" width="64" height="64"/><rect x="1024.5" y="412.5" width="64" height="64"/><rect x="1088.5" y="348.5" width="64" height="64"/><rect x="1088.5" y="412.5" width="64" height="64"/><rect x="768.5" y="476.5" width="64" height="64"/><rect x="768.5" y="540.5" width="64" height="64"/><rect x="832.5" y="476.5" width="64" height="64"/><rect x="832.5" y="540.5" width="64" height="64"/><rect x="896.5" y="476.5" width="64" height="64"/><rect x="896.5" y="540.5" width="64" height="64"/><rect x="960.5" y="476.5" width="64" height="64"/><rect x="960.5" y="540.5" width="64" height="64"/><rect x="768.5" y="604.5" width="64" height="64"/><rect x="768.5" y="668.5" width="64" height="64"/><rect x="832.5" y="604.5" width="64" height="64"/><rect x="832.5" y="668.5" width="64" height="64"/><rect x="1024.5" y="604.5" width="64" height="64"/><rect x="1024.5" y="668.5" width="64" height="64"/><rect x="1088.5" y="604.5" width="64" height="64"/><rect x="1088.5" y="668.5" width="64" height="64"/><rect x="320.5" y="156.5" width="64" height="64"/><rect x="384.5" y="220.5" width="64" height="64"/><rect x="256.5" y="284.5" width="64" height="64"/><rect x="320.5" y="284.5" width="64" height="64"/><rect x="384.5" y="284.5" width="64" height="64"/><rect x="1536.5" y="220.5" width="64" height="64"/><rect x="1472.5" y="284.5" width="64" height="64"/><rect x="1600.5" y="348.5" width="64" height="64"/><rect x="1536.5" y="348.5" width="64" height="64"/><rect x="1472.5" y="348.5" width="64" height="64"/><rect x="448.5" y="860.5" width="64" height="64"/><rect x="512.5" y="796.5" width="64" height="64"/><rect x="384.5" y="732.5" width="64" height="64"/><rect x="448.5" y="732.5" width="64" height="64"/><rect x="512.5" y="732.5" width="64" height="64"/><rect x="1344.5" y="796.5" width="64" height="64"/><rect x="1408.5" y="796.5" width="64" height="64"/><rect x="1472.5" y="796.5" width="64" height="64"/><rect x="1664.5" y="540.5" width="64" height="64"/><rect x="1728.5" y="540.5" width="64" height="64"/><rect x="1664.5" y="604.5" width="64" height="64"/><rect x="1728.5" y="604.5" width="64" height="64"/></g>
12
+ <g font-family="Geist Mono, monospace" font-size="5" font-weight="600" fill="#3eeba3"><text x="774" y="233">AGENT-73</text><text x="774" y="276">CODING</text><text x="774" y="297">AGENT-45</text><text x="774" y="340">DEPLOYING</text><text x="838" y="233">AGENT-10</text><text x="838" y="276">LINTING</text><text x="838" y="297">AGENT-82</text><text x="838" y="340">MERGING</text><text x="902" y="233">AGENT-47</text><text x="902" y="276">REFACTORING</text><text x="902" y="297">AGENT-19</text><text x="902" y="340">CODING</text><text x="966" y="233">AGENT-84</text><text x="966" y="276">RUNNING TESTS</text><text x="966" y="297">AGENT-56</text><text x="966" y="340">LINTING</text><text x="1030" y="361">AGENT-65</text><text x="1030" y="404">CODING</text><text x="1030" y="425">AGENT-37</text><text x="1030" y="468">DEPLOYING</text><text x="1094" y="361">AGENT-02</text><text x="1094" y="404">LINTING</text><text x="1094" y="425">AGENT-74</text><text x="1094" y="468">MERGING</text><text x="774" y="489">AGENT-61</text><text x="774" y="532">DEPLOYING</text><text x="774" y="553">AGENT-33</text><text x="774" y="596">REFACTORING</text><text x="838" y="489">AGENT-98</text><text x="838" y="532">MERGING</text><text x="838" y="553">AGENT-70</text><text x="838" y="596">RUNNING TESTS</text><text x="902" y="489">AGENT-35</text><text x="902" y="532">CODING</text><text x="902" y="553">AGENT-07</text><text x="902" y="596">DEPLOYING</text><text x="966" y="489">AGENT-72</text><text x="966" y="532">LINTING</text><text x="966" y="553">AGENT-44</text><text x="966" y="596">MERGING</text><text x="774" y="617">AGENT-05</text><text x="774" y="660">CODING</text><text x="774" y="681">AGENT-77</text><text x="774" y="724">DEPLOYING</text><text x="838" y="617">AGENT-42</text><text x="838" y="660">LINTING</text><text x="838" y="681">AGENT-14</text><text x="838" y="724">MERGING</text><text x="1030" y="617">AGENT-53</text><text x="1030" y="660">DEPLOYING</text><text x="1030" y="681">AGENT-25</text><text x="1030" y="724">REFACTORING</text><text x="1094" y="617">AGENT-90</text><text x="1094" y="660">MERGING</text><text x="1094" y="681">AGENT-62</text><text x="1094" y="724">RUNNING TESTS</text><text x="326" y="169">AGENT-42</text><text x="326" y="212">LINTING</text><text x="390" y="233">AGENT-51</text><text x="390" y="276">CODING</text><text x="262" y="297">AGENT-49</text><text x="262" y="340">REFACTORING</text><text x="326" y="297">AGENT-86</text><text x="326" y="340">RUNNING TESTS</text><text x="390" y="297">AGENT-23</text><text x="390" y="340">DEPLOYING</text><text x="1542" y="233">AGENT-17</text><text x="1542" y="276">CODING</text><text x="1478" y="297">AGENT-52</text><text x="1478" y="340">RUNNING TESTS</text><text x="1606" y="361">AGENT-98</text><text x="1606" y="404">RUNNING TESTS</text><text x="1542" y="361">AGENT-61</text><text x="1542" y="404">REFACTORING</text><text x="1478" y="361">AGENT-24</text><text x="1478" y="404">LINTING</text><text x="454" y="873">AGENT-08</text><text x="454" y="916">MERGING</text><text x="518" y="809">AGENT-73</text><text x="518" y="852">REFACTORING</text><text x="390" y="745">AGENT-27</text><text x="390" y="788">REFACTORING</text><text x="454" y="745">AGENT-64</text><text x="454" y="788">RUNNING TESTS</text><text x="518" y="745">AGENT-01</text><text x="518" y="788">DEPLOYING</text><text x="1350" y="809">AGENT-54</text><text x="1350" y="852">RUNNING TESTS</text><text x="1414" y="809">AGENT-91</text><text x="1414" y="852">DEPLOYING</text><text x="1478" y="809">AGENT-28</text><text x="1478" y="852">MERGING</text><text x="1670" y="553">AGENT-51</text><text x="1670" y="596">DEPLOYING</text><text x="1734" y="553">AGENT-88</text><text x="1734" y="596">MERGING</text><text x="1670" y="617">AGENT-23</text><text x="1670" y="660">REFACTORING</text><text x="1734" y="617">AGENT-60</text><text x="1734" y="660">RUNNING TESTS</text></g>
13
+ <path transform="translate(893.05 842)" fill="#ffffff" fill-opacity="0.85" d="M5.3 0H3.3V-28.7H13.2Q17.5 -28.7 20 -26.5Q22.6 -24.3 22.6 -20.2Q22.6 -16.9 20.5 -14.6Q18.4 -12.4 14.9 -12L23.3 0H20.9L12.8 -11.8H5.3ZM5.3 -27.1V-13.4H13Q16.5 -13.4 18.5 -15.2Q20.6 -17 20.6 -20.2Q20.6 -23.5 18.5 -25.3Q16.5 -27.1 13 -27.1Z M33.8 0.4Q31 0.4 28.8 -0.9Q26.6 -2.3 25.4 -4.9Q24.2 -7.4 24.2 -10.7Q24.2 -13.7 25.5 -16.2Q26.7 -18.6 28.8 -20Q30.9 -21.4 33.6 -21.4Q35.8 -21.4 37.5 -20.6Q39.2 -19.7 40.5 -18.2Q41.7 -16.7 42.3 -14.7Q42.9 -12.6 42.8 -10.1H25.2V-11.5H40.9Q40.7 -15.4 38.8 -17.7Q36.8 -19.9 33.6 -19.9Q31.4 -19.9 29.7 -18.7Q28 -17.6 27 -15.5Q26.1 -13.5 26.1 -10.7Q26.1 -7.8 27 -5.6Q27.9 -3.4 29.7 -2.3Q31.4 -1.1 33.8 -1.1Q36.7 -1.1 38.6 -2.7Q40.6 -4.3 41.1 -7.1H42.9Q42.3 -3.6 39.8 -1.6Q37.4 0.4 33.8 0.4Z M64.2 -10.5Q64.2 -7.2 63.1 -4.8Q61.9 -2.3 59.9 -1Q57.8 0.4 55 0.4Q52.5 0.4 50.5 -1Q48.5 -2.4 47.4 -4.8V7.7H45.5V-21H47.3V-15.9Q48.3 -18.5 50.4 -19.9Q52.5 -21.4 55 -21.4Q57.8 -21.4 59.9 -20Q61.9 -18.7 63.1 -16.2Q64.2 -13.8 64.2 -10.5ZM62.3 -10.5Q62.3 -14.8 60.3 -17.3Q58.3 -19.8 54.8 -19.8Q52.7 -19.8 51 -18.7Q49.3 -17.6 48.3 -15.5Q47.3 -13.5 47.3 -10.5Q47.3 -7.7 48.3 -5.6Q49.2 -3.5 50.9 -2.3Q52.6 -1.2 54.8 -1.2Q58.3 -1.2 60.3 -3.6Q62.3 -6.1 62.3 -10.5Z M68.7 0H66.8V-28.7H68.7Z M74.8 0H72.9V-21H74.8ZM75.6 -25.8Q75.6 -25.1 75.2 -24.6Q74.7 -24.1 73.9 -24.1Q73.1 -24.1 72.6 -24.6Q72.1 -25.1 72.1 -25.8Q72.1 -26.6 72.6 -27Q73.1 -27.5 73.9 -27.5Q74.7 -27.5 75.2 -27Q75.6 -26.6 75.6 -25.8Z M86.5 0.4Q83.8 0.4 81.8 -0.9Q79.7 -2.3 78.6 -4.8Q77.4 -7.3 77.4 -10.5Q77.4 -13.7 78.6 -16.2Q79.7 -18.6 81.8 -20Q83.9 -21.4 86.5 -21.4Q88.9 -21.4 90.7 -20.4Q92.6 -19.4 93.8 -17.6Q95 -15.7 95.5 -13.2H93.6Q93 -16.3 91.2 -18.1Q89.3 -19.8 86.5 -19.8Q84.4 -19.8 82.8 -18.6Q81.1 -17.4 80.2 -15.4Q79.3 -13.3 79.3 -10.5Q79.3 -7.7 80.2 -5.6Q81.1 -3.5 82.8 -2.3Q84.4 -1.1 86.5 -1.1Q89.3 -1.1 91.2 -2.9Q93.1 -4.7 93.6 -7.8H95.5Q95.1 -5.2 93.8 -3.4Q92.6 -1.6 90.8 -0.6Q88.9 0.4 86.5 0.4Z M111.1 0V-4.2Q110.3 -2.1 108.3 -0.9Q106.4 0.4 103.9 0.4Q100.6 0.4 98.7 -1.3Q96.7 -2.9 96.7 -5.7Q96.7 -8.8 99.2 -10.4Q101.6 -11.9 106.4 -11.9Q107.4 -11.9 108.3 -11.9Q109.3 -11.8 111 -11.7V-13.6Q111 -16.6 109.5 -18.2Q108.1 -19.9 105.4 -19.9Q102.6 -19.9 100.9 -18.2Q99.3 -16.5 99.2 -13.7H97.5Q97.5 -16 98.5 -17.7Q99.5 -19.4 101.3 -20.4Q103.1 -21.4 105.4 -21.4Q108.9 -21.4 110.9 -19.4Q112.8 -17.4 112.8 -13.8V0ZM98.6 -5.8Q98.6 -3.7 100.1 -2.4Q101.6 -1 104 -1Q107.2 -1 109.1 -3.1Q111 -5.1 111 -8.4V-10.4Q109.5 -10.5 108.5 -10.5Q107.4 -10.6 106.5 -10.6Q102.5 -10.6 100.5 -9.4Q98.6 -8.2 98.6 -5.8Z M131.9 -5.5Q131.9 -2.8 129.8 -1.2Q127.7 0.4 123.9 0.4Q120.3 0.4 118 -1.4Q115.8 -3.2 115.5 -6.4H117.3Q117.4 -3.9 119.2 -2.5Q121 -1.1 124 -1.1Q126.9 -1.1 128.5 -2.2Q130 -3.3 130 -5.3Q130 -7.1 128.9 -8Q127.8 -8.9 125.2 -9.4L122.4 -10Q119.3 -10.6 117.8 -12Q116.3 -13.4 116.3 -15.6Q116.3 -17.3 117.2 -18.6Q118.2 -19.9 119.8 -20.6Q121.5 -21.4 123.7 -21.4Q126 -21.4 127.7 -20.6Q129.5 -19.8 130.5 -18.3Q131.5 -16.8 131.7 -14.8H129.9Q129.7 -17.2 128 -18.6Q126.4 -19.9 123.7 -19.9Q121.2 -19.9 119.6 -18.8Q118.1 -17.7 118.1 -15.8Q118.1 -14 119.2 -13.1Q120.4 -12.1 123 -11.6L125.9 -11Q129 -10.4 130.5 -9.1Q131.9 -7.8 131.9 -5.5Z"/>
14
+ <g font-family="Geist Mono, monospace" font-size="14" fill="#ffffff" fill-opacity="0.4" text-anchor="middle"><text x="14" y="22">+</text><text x="1906" y="22">+</text><text x="14" y="1070">+</text><text x="1906" y="1070">+</text></g>
15
+ <text x="34" y="22" font-family="Geist Mono, monospace" font-size="10" letter-spacing="1.4" fill="#ffffff" fill-opacity="0.45">REPLICAS / DESKTOP</text>
54
16
  </svg>
@@ -1,10 +1,10 @@
1
1
  [Settings]
2
- gtk-theme-name=Yaru-dark
3
- gtk-icon-theme-name=Yaru
2
+ gtk-theme-name=@GTK_THEME_NAME@
3
+ gtk-icon-theme-name=Yaru-viridian
4
4
  gtk-cursor-theme-name=Bibata-Modern-Ice
5
5
  gtk-cursor-theme-size=22
6
- gtk-font-name=Cantarell 11
7
- gtk-application-prefer-dark-theme=1
6
+ gtk-font-name=General Sans 10
7
+ gtk-application-prefer-dark-theme=@GTK_PREFER_DARK@
8
8
  gtk-xft-antialias=1
9
9
  gtk-xft-hinting=1
10
10
  gtk-xft-hintstyle=hintslight
@@ -0,0 +1,6 @@
1
+ [Desktop Entry]
2
+ Type=Application
3
+ Name=Text Editor
4
+ Exec=mousepad %U
5
+ Icon=accessories-text-editor
6
+ StartupNotify=true
@@ -0,0 +1,6 @@
1
+ [Desktop Entry]
2
+ Type=Application
3
+ Name=Files
4
+ Exec=thunar %U
5
+ Icon=system-file-manager
6
+ StartupNotify=true
@@ -0,0 +1,6 @@
1
+ [Desktop Entry]
2
+ Type=Application
3
+ Name=Terminal
4
+ Exec=/usr/local/bin/replicas-terminal
5
+ Icon=utilities-terminal
6
+ StartupNotify=true
@@ -4,13 +4,21 @@
4
4
  <meta charset="utf-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
6
6
  <title>Replicas Desktop</title>
7
+ <script src="./viewer-theme.js"></script>
8
+ <link rel="stylesheet" href="./viewer-theme.css">
7
9
  <link rel="stylesheet" href="./viewer.css">
8
10
  <link rel="icon" href="./viewer-icon.svg" type="image/svg+xml">
9
11
  </head>
10
12
  <body>
11
13
  <div id="screen"></div>
12
14
  <div id="status" class="visible" role="status" aria-live="polite">
15
+ <span class="frame-corner" aria-hidden="true">+</span>
16
+ <span class="frame-corner" aria-hidden="true">+</span>
17
+ <span class="frame-corner" aria-hidden="true">+</span>
18
+ <span class="frame-corner" aria-hidden="true">+</span>
19
+ <span class="frame-label" aria-hidden="true">Replicas / Desktop</span>
13
20
  <img src="./viewer-icon.svg" alt="">
21
+ <span id="status-title" aria-hidden="true">Replicas</span>
14
22
  <span id="status-text">connecting…</span>
15
23
  </div>
16
24
  <div id="hint">This desktop runs Linux — ⌘ shortcuts won't work here. Use Ctrl instead (e.g. Ctrl+C / Ctrl+V).</div>
@@ -24,26 +24,26 @@
24
24
  <keepBorder>yes</keepBorder>
25
25
  <animateIconify>yes</animateIconify>
26
26
  <font place="ActiveWindow">
27
- <name>Cantarell</name>
28
- <size>11</size>
27
+ <name>General Sans</name>
28
+ <size>10</size>
29
29
  <weight>bold</weight>
30
30
  <slant>normal</slant>
31
31
  </font>
32
32
  <font place="InactiveWindow">
33
- <name>Cantarell</name>
34
- <size>11</size>
33
+ <name>General Sans</name>
34
+ <size>10</size>
35
35
  <weight>bold</weight>
36
36
  <slant>normal</slant>
37
37
  </font>
38
38
  <font place="MenuHeader">
39
- <name>Cantarell</name>
40
- <size>11</size>
39
+ <name>General Sans</name>
40
+ <size>10</size>
41
41
  <weight>normal</weight>
42
42
  <slant>normal</slant>
43
43
  </font>
44
44
  <font place="MenuItem">
45
- <name>Cantarell</name>
46
- <size>11</size>
45
+ <name>General Sans</name>
46
+ <size>10</size>
47
47
  <weight>normal</weight>
48
48
  <slant>normal</slant>
49
49
  </font>
@@ -1,37 +1,37 @@
1
1
  border.width: 1
2
- padding.width: 5
3
- padding.height: 8
4
- window.client.padding.width: 1
5
- window.client.padding.height: 1
2
+ padding.width: 6
3
+ padding.height: 7
4
+ window.client.padding.width: 0
5
+ window.client.padding.height: 0
6
6
  window.handle.width: 0
7
7
  window.label.text.justify: center
8
8
 
9
- window.active.border.color: #111827
10
- window.inactive.border.color: #1f2937
11
- window.*.client.color: #ffffff
9
+ window.active.border.color: @BORDER@
10
+ window.inactive.border.color: @BORDER_MUTED@
11
+ window.*.client.color: @SURFACE_ALT@
12
12
  window.*.title.bg: flat
13
- window.active.title.bg.color: #111827
14
- window.inactive.title.bg.color: #273142
13
+ window.active.title.bg.color: @SURFACE@
14
+ window.inactive.title.bg.color: @SURFACE_ALT@
15
15
  window.active.label.bg: parentrelative
16
16
  window.inactive.label.bg: parentrelative
17
17
  window.active.button.*.bg: flat
18
- window.active.button.*.bg.color: #111827
18
+ window.active.button.*.bg.color: @SURFACE@
19
19
  window.inactive.button.*.bg: flat
20
- window.inactive.button.*.bg.color: #273142
21
- window.active.button.*.image.color: #f8fafc
22
- window.inactive.button.*.image.color: #cbd5e1
20
+ window.inactive.button.*.bg.color: @SURFACE_ALT@
21
+ window.active.button.*.image.color: @INK@
22
+ window.inactive.button.*.image.color: @INK_FAINT@
23
23
  window.active.button.*.hover.bg: flat
24
- window.active.button.*.hover.bg.color: #334155
24
+ window.active.button.*.hover.bg.color: @SURFACE_RAISED@
25
25
  window.inactive.button.*.hover.bg: flat
26
- window.inactive.button.*.hover.bg.color: #334155
27
- window.active.button.*.hover.image.color: #ffffff
28
- window.inactive.button.*.hover.image.color: #ffffff
29
- window.active.button.*.pressed.image.color: #38bdf8
30
- window.inactive.button.*.pressed.image.color: #38bdf8
31
- window.active.label.text.color: #f8fafc
32
- window.inactive.label.text.color: #d1d5db
33
- window.active.title.separator.color: #111827
34
- window.inactive.title.separator.color: #273142
26
+ window.inactive.button.*.hover.bg.color: @SURFACE_RAISED@
27
+ window.active.button.*.hover.image.color: @INK_STRONG@
28
+ window.inactive.button.*.hover.image.color: @INK_STRONG@
29
+ window.active.button.*.pressed.image.color: @ACCENT_INK@
30
+ window.inactive.button.*.pressed.image.color: @ACCENT_INK@
31
+ window.active.label.text.color: @INK@
32
+ window.inactive.label.text.color: @INK_MUTED@
33
+ window.active.title.separator.color: @SURFACE@
34
+ window.inactive.title.separator.color: @SURFACE_ALT@
35
35
 
36
36
  menu.border.width: 1
37
37
  menu.separator.width: 1
@@ -39,28 +39,28 @@ menu.separator.padding.width: 6
39
39
  menu.separator.padding.height: 4
40
40
  menu.overlap.x: 0
41
41
  menu.overlap.y: 0
42
- menu.border.color: #1f2937
43
- menu.separator.color: #334155
44
- menu.items.text.color: #e5e7eb
45
- menu.items.disabled.text.color: #64748b
46
- menu.items.active.text.color: #ffffff
47
- menu.items.active.disabled.text.color: #94a3b8
42
+ menu.border.color: @BORDER@
43
+ menu.separator.color: @BORDER@
44
+ menu.items.text.color: @INK@
45
+ menu.items.disabled.text.color: @INK_DISABLED@
46
+ menu.items.active.text.color: #121212
47
+ menu.items.active.disabled.text.color: #1c6a49
48
48
  menu.items.bg: flat
49
- menu.items.bg.color: #111827
49
+ menu.items.bg.color: @SURFACE@
50
50
  menu.items.active.bg: flat
51
- menu.items.active.bg.color: #2563eb
52
- menu.title.text.color: #f8fafc
51
+ menu.items.active.bg.color: @ACCENT@
52
+ menu.title.text.color: @INK_MUTED@
53
53
  menu.title.bg: flat
54
- menu.title.bg.color: #0f172a
54
+ menu.title.bg.color: @SURFACE_ALT@
55
55
 
56
56
  osd.border.width: 1
57
- osd.border.color: #334155
57
+ osd.border.color: @BORDER@
58
58
  osd.bg: flat
59
- osd.bg.color: #111827
59
+ osd.bg.color: @SURFACE@
60
60
  osd.hilight.bg: flat
61
- osd.hilight.bg.color: #2563eb
61
+ osd.hilight.bg.color: @ACCENT@
62
62
  osd.unhilight.bg: flat
63
- osd.unhilight.bg.color: #1f2937
63
+ osd.unhilight.bg.color: @SURFACE_RAISED@
64
64
  osd.label.bg: flat
65
- osd.label.bg.color: #111827
66
- osd.label.text.color: #f8fafc
65
+ osd.label.bg.color: @SURFACE@
66
+ osd.label.text.color: @INK@
@@ -0,0 +1,16 @@
1
+ #!/bin/bash
2
+ # xfce4-terminal 1.1 keeps its settings in xfconf, which needs a session bus this
3
+ # desktop does not run, so the theme is applied per launch instead of via terminalrc.
4
+ STATE_DIR="${REPLICAS_DESKTOP_STATE_DIR:-/tmp/replicas-computer}"
5
+ TEMPLATES="${REPLICAS_DESKTOP_TEMPLATES:-/usr/local/share/replicas/desktop}"
6
+ THEME="$(cat "$STATE_DIR/theme" 2>/dev/null)"
7
+ [ -f "$TEMPLATES/themes/$THEME.env" ] || THEME=dark
8
+ . "$TEMPLATES/themes/$THEME.env"
9
+ exec xfce4-terminal \
10
+ --font='Geist Mono 11' \
11
+ --color-bg="$SURFACE_ALT" \
12
+ --color-text="$INK" \
13
+ --hide-menubar \
14
+ --hide-toolbar \
15
+ --hide-scrollbar \
16
+ "$@"
@@ -43,6 +43,8 @@ LOCK_BUSY_EXIT_CODE="${REPLICAS_DESKTOP_LOCK_BUSY_EXIT_CODE:-75}"
43
43
  LOCK_FILE="${REPLICAS_DESKTOP_LOCK_FILE:-$STATE_DIR/services-start.lock}"
44
44
 
45
45
  mkdir -p "$STATE_DIR"
46
+ REQUESTED_THEME=""
47
+ [ "$1" = "--theme" ] && REQUESTED_THEME="$2"
46
48
 
47
49
  acquire_start_lock() {
48
50
  if command -v flock >/dev/null 2>&1; then
@@ -264,13 +266,12 @@ clear_bridge_pid_if_unhealthy() {
264
266
  }
265
267
 
266
268
  paint_wallpaper() {
267
- local wallpaper="${REPLICAS_DESKTOP_WALLPAPER:-$REPLICAS_DESKTOP_TEMPLATES/brand-wallpaper.svg}"
268
- local rendered_wallpaper="$STATE_DIR/wallpaper-${WIDTH}x${HEIGHT}.png"
269
- local dock_height="${REPLICAS_DESKTOP_DOCK_HEIGHT:-92}"
269
+ local wallpaper="${REPLICAS_DESKTOP_WALLPAPER:-$REPLICAS_DESKTOP_TEMPLATES/$WALLPAPER}"
270
+ local rendered_wallpaper="$STATE_DIR/wallpaper-$THEME-${WIDTH}x${HEIGHT}.png"
270
271
  if command -v ffmpeg >/dev/null 2>&1 && [ -f "$wallpaper" ] && [ ! -f "$rendered_wallpaper" ]; then
271
272
  ffmpeg -y -loglevel error \
272
273
  -i "$wallpaper" \
273
- -vf "scale=${WIDTH}:${HEIGHT}:force_original_aspect_ratio=increase,crop=${WIDTH}:${HEIGHT},drawbox=x=0:y=ih-${dock_height}:w=iw:h=${dock_height}:color=0x0b1020@0.86:t=fill" \
274
+ -vf "scale=${WIDTH}:${HEIGHT}:force_original_aspect_ratio=increase,crop=${WIDTH}:${HEIGHT}" \
274
275
  -frames:v 1 "$rendered_wallpaper" >/dev/null 2>&1 || true
275
276
  fi
276
277
 
@@ -279,21 +280,35 @@ paint_wallpaper() {
279
280
  elif command -v hsetroot >/dev/null 2>&1 && [ -f "$wallpaper" ]; then
280
281
  DISPLAY=":$DISPLAY_NUM" hsetroot -cover "$wallpaper" >/dev/null 2>&1 || true
281
282
  elif command -v hsetroot >/dev/null 2>&1; then
282
- DISPLAY=":$DISPLAY_NUM" hsetroot -solid '#0d1117' >/dev/null 2>&1 || true
283
+ DISPLAY=":$DISPLAY_NUM" hsetroot -solid "$SURFACE_ALT" >/dev/null 2>&1 || true
283
284
  else
284
- DISPLAY=":$DISPLAY_NUM" xsetroot -solid '#0d1117' >/dev/null 2>&1 || true
285
+ DISPLAY=":$DISPLAY_NUM" xsetroot -solid "$SURFACE_ALT" >/dev/null 2>&1 || true
285
286
  fi
286
287
  DISPLAY=":$DISPLAY_NUM" xsetroot -cursor_name left_ptr >/dev/null 2>&1 || true
287
288
  }
288
289
 
289
290
  acquire_start_lock
290
291
 
292
+ REPLICAS_DESKTOP_TEMPLATES="${REPLICAS_DESKTOP_TEMPLATES:-/usr/local/share/replicas/desktop}"
293
+ PREVIOUS_THEME="$(cat "$STATE_DIR/theme" 2>/dev/null)"
294
+ THEME="${REQUESTED_THEME:-${PREVIOUS_THEME:-${REPLICAS_DESKTOP_THEME:-dark}}}"
295
+ [ -f "$REPLICAS_DESKTOP_TEMPLATES/themes/$THEME.env" ] || THEME=dark
296
+ . "$REPLICAS_DESKTOP_TEMPLATES/themes/$THEME.env"
297
+ echo "$THEME" > "$STATE_DIR/theme"
298
+
299
+ render_template() {
300
+ local expr="s|/usr/local/share/replicas/desktop|$REPLICAS_DESKTOP_TEMPLATES|g" key
301
+ for key in $(grep -o '^[A-Z_]*' "$REPLICAS_DESKTOP_TEMPLATES/themes/$THEME.env"); do
302
+ expr="$expr;s|@$key@|${!key}|g"
303
+ done
304
+ sed "$expr" "$1" > "$2"
305
+ }
306
+
291
307
  export XCURSOR_THEME="${XCURSOR_THEME:-Bibata-Modern-Ice}"
292
308
  export XCURSOR_SIZE="${XCURSOR_SIZE:-22}"
293
- export GTK_THEME="${GTK_THEME:-Yaru-dark}"
294
- export GTK_ICON_THEME="${GTK_ICON_THEME:-Yaru}"
309
+ export GTK_THEME="$GTK_THEME_NAME"
310
+ export GTK_ICON_THEME="${GTK_ICON_THEME:-Yaru-viridian}"
295
311
 
296
- REPLICAS_DESKTOP_TEMPLATES="${REPLICAS_DESKTOP_TEMPLATES:-/usr/local/share/replicas/desktop}"
297
312
  mkdir -p \
298
313
  "$HOME/.config/tint2" \
299
314
  "$HOME/.config/openbox" \
@@ -302,16 +317,20 @@ mkdir -p \
302
317
  "$HOME/.themes/Replicas-modern/openbox-3" \
303
318
  "$HOME/.icons/default"
304
319
 
305
- [ -f "$REPLICAS_DESKTOP_TEMPLATES/tint2rc" ] && cp "$REPLICAS_DESKTOP_TEMPLATES/tint2rc" "$HOME/.config/tint2/tint2rc"
320
+ [ -f "$REPLICAS_DESKTOP_TEMPLATES/tint2rc" ] && render_template "$REPLICAS_DESKTOP_TEMPLATES/tint2rc" "$HOME/.config/tint2/tint2rc"
306
321
  [ -f "$REPLICAS_DESKTOP_TEMPLATES/openbox-rc.xml" ] && cp "$REPLICAS_DESKTOP_TEMPLATES/openbox-rc.xml" "$HOME/.config/openbox/rc.xml"
307
322
  [ -f "$REPLICAS_DESKTOP_TEMPLATES/picom.conf" ] && cp "$REPLICAS_DESKTOP_TEMPLATES/picom.conf" "$HOME/.config/picom/picom.conf"
308
- [ -f "$REPLICAS_DESKTOP_TEMPLATES/gtk-settings.ini" ] && cp "$REPLICAS_DESKTOP_TEMPLATES/gtk-settings.ini" "$HOME/.config/gtk-3.0/settings.ini"
323
+ [ -f "$REPLICAS_DESKTOP_TEMPLATES/gtk-settings.ini" ] && render_template "$REPLICAS_DESKTOP_TEMPLATES/gtk-settings.ini" "$HOME/.config/gtk-3.0/settings.ini"
309
324
  if [ -d "$REPLICAS_DESKTOP_TEMPLATES/openbox-theme" ]; then
310
- cp "$REPLICAS_DESKTOP_TEMPLATES/openbox-theme/"* "$HOME/.themes/Replicas-modern/openbox-3/" 2>/dev/null || true
325
+ cp "$REPLICAS_DESKTOP_TEMPLATES/openbox-theme/"*.xbm "$HOME/.themes/Replicas-modern/openbox-3/" 2>/dev/null || true
326
+ render_template "$REPLICAS_DESKTOP_TEMPLATES/openbox-theme/themerc" "$HOME/.themes/Replicas-modern/openbox-3/themerc"
311
327
  fi
312
328
  if [ -f "$REPLICAS_DESKTOP_TEMPLATES/replicas-chrome" ]; then
313
329
  sudo install -m 0755 "$REPLICAS_DESKTOP_TEMPLATES/replicas-chrome" /usr/local/bin/replicas-chrome 2>/dev/null || true
314
330
  fi
331
+ if [ -f "$REPLICAS_DESKTOP_TEMPLATES/replicas-terminal" ]; then
332
+ sudo install -m 0755 "$REPLICAS_DESKTOP_TEMPLATES/replicas-terminal" /usr/local/bin/replicas-terminal 2>/dev/null || true
333
+ fi
315
334
  if [ -f "$REPLICAS_DESKTOP_TEMPLATES/replicas-chrome.desktop" ]; then
316
335
  sudo install -m 0644 "$REPLICAS_DESKTOP_TEMPLATES/replicas-chrome.desktop" /usr/share/applications/replicas-chrome.desktop 2>/dev/null || true
317
336
  fi
@@ -345,6 +364,12 @@ start_bg openbox \
345
364
  sleep 0.2
346
365
  paint_wallpaper
347
366
 
367
+ if [ -n "$REQUESTED_THEME" ] && [ "$THEME" != "$PREVIOUS_THEME" ]; then
368
+ DISPLAY=":$DISPLAY_NUM" openbox --reconfigure >/dev/null 2>&1 || true
369
+ kill_pids "$(cat "$STATE_DIR/tint2.pid" 2>/dev/null)"
370
+ rm -f "$STATE_DIR/tint2.pid"
371
+ fi
372
+
348
373
  # tint2 panel anchors window stacking on bare openbox.
349
374
  start_bg tint2 \
350
375
  "false" \
@@ -4,13 +4,21 @@
4
4
  <meta charset="utf-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
6
6
  <title>Replicas Desktop</title>
7
+ <script src="./viewer-theme.js"></script>
8
+ <link rel="stylesheet" href="./viewer-theme.css">
7
9
  <link rel="stylesheet" href="./stream-viewer.css">
8
10
  <link rel="icon" href="./viewer-icon.svg" type="image/svg+xml">
9
11
  </head>
10
12
  <body>
11
13
  <video id="screen" tabindex="0" aria-label="Replicas desktop" autoplay muted playsinline></video>
12
14
  <div id="status" class="visible" role="status" aria-live="polite">
15
+ <span class="frame-corner" aria-hidden="true">+</span>
16
+ <span class="frame-corner" aria-hidden="true">+</span>
17
+ <span class="frame-corner" aria-hidden="true">+</span>
18
+ <span class="frame-corner" aria-hidden="true">+</span>
19
+ <span class="frame-label" aria-hidden="true">Replicas / Desktop</span>
13
20
  <img src="./viewer-icon.svg" alt="">
21
+ <span id="status-title" aria-hidden="true">Replicas</span>
14
22
  <span id="status-text">connecting…</span>
15
23
  </div>
16
24
  <button id="audio-prompt" type="button">Enable audio</button>
@@ -1,63 +1,33 @@
1
- @font-face {
2
- font-family: "Geist Mono";
3
- font-style: normal;
4
- font-weight: 400 600;
5
- font-display: swap;
6
- src: url("./geist-mono.woff2") format("woff2");
7
- }
8
-
9
- html, body {
10
- width: 100%;
11
- height: 100%;
12
- margin: 0;
13
- overflow: hidden;
14
- background: #050706;
15
- font-family: "Geist Mono", ui-monospace, monospace;
16
- }
17
-
1
+ html, body { background: var(--replicas-surface); }
18
2
  body { display: grid; place-items: center; }
19
3
 
20
4
  #screen {
21
5
  display: block;
22
6
  outline: none;
23
- background: #050706;
7
+ background: var(--replicas-surface);
24
8
  cursor: default;
25
9
  touch-action: none;
26
10
  }
27
11
 
28
- #status {
29
- position: fixed;
30
- inset: 0;
31
- display: flex;
32
- gap: 16px;
33
- align-items: center;
34
- justify-content: center;
35
- color: rgb(255 255 255 / 92%);
36
- background: radial-gradient(circle at 18% 20%, rgb(62 235 163 / 16%), transparent 34%),
37
- radial-gradient(circle at 84% 78%, rgb(8 44 37 / 85%), transparent 42%),
38
- linear-gradient(135deg, #1b9179 0%, #1d8570 13%, #082b24 100%);
39
- font-size: 24px;
40
- pointer-events: none;
41
- opacity: 0;
42
- transition: opacity 180ms ease-out;
43
- }
44
-
45
- #status.visible { opacity: 1; }
46
- #status img { width: 52px; height: 52px; filter: drop-shadow(0 2px 16px rgb(62 235 163 / 50%)); }
12
+ #status { background: var(--replicas-grid); }
47
13
 
48
14
  #audio-prompt {
49
15
  position: fixed;
50
16
  right: 16px;
51
17
  bottom: 16px;
52
- padding: 8px 12px;
53
- border: 1px solid rgb(255 255 255 / 20%);
54
- border-radius: 6px;
55
- color: white;
56
- background: rgb(13 17 23 / 88%);
57
- font: inherit;
18
+ height: 32px;
19
+ padding: 0 12px;
20
+ border: 1px solid var(--replicas-hairline-strong);
21
+ border-radius: 0;
22
+ color: var(--replicas-ink);
23
+ background: var(--replicas-surface);
24
+ font: 700 11px/1 "Geist Mono", ui-monospace, monospace;
25
+ letter-spacing: 0.06em;
26
+ text-transform: uppercase;
58
27
  cursor: pointer;
59
28
  }
60
29
 
30
+ #audio-prompt:hover, #audio-prompt:focus-visible { border-color: var(--replicas-green); color: var(--replicas-green); outline: none; }
61
31
  #audio-prompt[hidden] { display: none; }
62
32
 
63
33
  #diagnostics {
@@ -65,9 +35,10 @@ body { display: grid; place-items: center; }
65
35
  top: 12px;
66
36
  right: 12px;
67
37
  display: none;
68
- padding: 5px 8px;
69
- color: rgb(255 255 255 / 78%);
70
- background: rgb(0 0 0 / 58%);
38
+ padding: 6px 10px;
39
+ border: 1px solid var(--replicas-hairline);
40
+ color: var(--replicas-ink);
41
+ background: var(--replicas-panel);
71
42
  font-size: 11px;
72
43
  pointer-events: none;
73
44
  }
@@ -0,0 +1,17 @@
1
+ WALLPAPER='brand-wallpaper.svg'
2
+ GTK_THEME_NAME='Yaru-viridian-dark'
3
+ GTK_PREFER_DARK='1'
4
+ SURFACE='#171717'
5
+ SURFACE_ALT='#121212'
6
+ SURFACE_RAISED='#2b2b2b'
7
+ BORDER='#2b2d2c'
8
+ BORDER_MUTED='#242424'
9
+ INK='#ededed'
10
+ INK_STRONG='#ffffff'
11
+ INK_MUTED='#8a8a8a'
12
+ INK_FAINT='#6f6f6f'
13
+ INK_DISABLED='#5c5c5c'
14
+ LINE='#ffffff'
15
+ ACCENT='#3eeba3'
16
+ ACCENT_INK='#3eeba3'
17
+ MARK_ICON='viewer-icon.svg'
@@ -0,0 +1,17 @@
1
+ WALLPAPER='brand-wallpaper-light.svg'
2
+ GTK_THEME_NAME='Yaru-viridian'
3
+ GTK_PREFER_DARK='0'
4
+ SURFACE='#ffffff'
5
+ SURFACE_ALT='#f2f3f1'
6
+ SURFACE_RAISED='#e8ece7'
7
+ BORDER='#d9ded8'
8
+ BORDER_MUTED='#e2e6e0'
9
+ INK='#162118'
10
+ INK_STRONG='#000000'
11
+ INK_MUTED='#67706a'
12
+ INK_FAINT='#8a938d'
13
+ INK_DISABLED='#b9c1b8'
14
+ LINE='#162118'
15
+ ACCENT='#2fc487'
16
+ ACCENT_INK='#2f9d57'
17
+ MARK_ICON='viewer-icon-light.svg'
@@ -1,89 +1,138 @@
1
- panel_items = LTC
2
- panel_size = 100% 84
3
- panel_margin = 0 0
4
- panel_padding = 18 12 18
1
+ # Backgrounds come first: tint2 resolves *_background_id while parsing, so ids
2
+ # referenced before their definition silently fall back to transparent.
3
+ # id 1 -> panel_background_id
4
+ rounded = 18
5
+ border_width = 1
6
+ border_sides = TBLR
7
+ background_color = @SURFACE@ 100
8
+ border_color = @LINE@ 14
9
+ background_color_hover = @SURFACE@ 100
10
+ border_color_hover = @LINE@ 14
11
+ background_color_pressed = @SURFACE@ 100
12
+ border_color_pressed = @LINE@ 14
13
+
14
+ # id 2 -> launcher_icon_background_id
15
+ rounded = 12
16
+ border_width = 0
17
+ background_color = @LINE@ 0
18
+ border_color = #000000 0
19
+ background_color_hover = @LINE@ 10
20
+ border_color_hover = #000000 0
21
+ background_color_pressed = @LINE@ 6
22
+ border_color_pressed = #000000 0
23
+
24
+ # id 3 -> task_background_id, task_iconified_background_id
25
+ rounded = 12
26
+ border_width = 0
27
+ background_color = @LINE@ 8
28
+ border_color = #000000 0
29
+ background_color_hover = @LINE@ 13
30
+ border_color_hover = #000000 0
31
+ background_color_pressed = @LINE@ 6
32
+ border_color_pressed = #000000 0
33
+
34
+ # id 4 -> task_active_background_id, task_urgent_background_id
35
+ rounded = 12
36
+ border_width = 1
37
+ background_color = @ACCENT@ 12
38
+ border_color = @ACCENT@ 40
39
+ background_color_hover = @ACCENT@ 16
40
+ border_color_hover = @ACCENT@ 40
41
+ background_color_pressed = @ACCENT@ 10
42
+ border_color_pressed = @ACCENT@ 40
43
+
44
+ # id 5 -> tooltip_background_id
45
+ rounded = 6
46
+ border_width = 1
47
+ background_color = @SURFACE_ALT@ 96
48
+ border_color = @LINE@ 16
49
+
50
+ panel_items = PLT:C
51
+ panel_size = 100% 72
52
+ panel_margin = 0 12
53
+ panel_padding = 10 7 6
5
54
  panel_background_id = 1
6
- wm_menu = 0
7
- panel_dock = 0
55
+ panel_shrink = 1
8
56
  panel_position = bottom center horizontal
9
57
  panel_layer = top
10
58
  panel_monitor = all
11
- panel_shrink = 0
12
- strut_policy = follow_size
59
+ panel_window_name = tint2
13
60
  disable_transparency = 1
61
+ strut_policy = follow_size
62
+ wm_menu = 0
14
63
  font_shadow = 0
64
+ mouse_effects = 1
65
+ mouse_hover_icon_asb = 100 0 12
66
+ mouse_pressed_icon_asb = 100 0 -14
15
67
 
16
- rounded = 0
17
- rounded = 16
18
- border_width = 0
19
- background_color = #ffffff 14
20
- border_color = #000000 0
21
- rounded = 16
22
- border_width = 0
23
- background_color = #1a1a1a 0
24
- border_color = #000000 0
25
- rounded = 16
26
- border_width = 0
27
- background_color = #ffffff 10
28
- border_color = #000000 0
68
+ button = new
69
+ button_icon = /usr/local/share/replicas/desktop/@MARK_ICON@
70
+ button_tooltip = Replicas Desktop
71
+ button_background_id = 0
72
+ button_centered = 1
73
+ button_max_icon_size = 46
74
+ button_padding = 10 0
29
75
 
30
- launcher_padding = 12 0 12
31
- launcher_background_id = 1
32
- launcher_icon_background_id = 4
33
- launcher_icon_size = 54
76
+ launcher_padding = 4 0 6
77
+ launcher_background_id = 0
78
+ launcher_icon_background_id = 2
79
+ launcher_icon_size = 42
34
80
  launcher_icon_asb = 100 0 0
35
- launcher_icon_theme = Yaru
81
+ launcher_icon_theme = Yaru-viridian
82
+ launcher_tooltip = 1
36
83
  launcher_item_app = /usr/share/applications/replicas-chrome.desktop
37
- launcher_item_app = /usr/share/applications/thunar.desktop
38
- launcher_item_app = /usr/share/applications/xfce4-terminal.desktop
39
- launcher_item_app = /usr/share/applications/org.xfce.mousepad.desktop
84
+ launcher_item_app = /usr/local/share/replicas/desktop/launchers/files.desktop
85
+ launcher_item_app = /usr/local/share/replicas/desktop/launchers/terminal.desktop
86
+ launcher_item_app = /usr/local/share/replicas/desktop/launchers/editor.desktop
40
87
 
41
88
  taskbar_mode = single_desktop
42
- taskbar_padding = 16 0 16
89
+ taskbar_hide_if_empty = 1
90
+ taskbar_padding = 4 0 4
43
91
  taskbar_background_id = 0
44
92
  taskbar_active_background_id = 0
45
93
  taskbar_name = 0
46
94
  taskbar_distribute_size = 0
47
95
  taskbar_sort_order = none
48
96
 
49
- systray_padding = 8 0 8
50
- systray_background_id = 1
51
- systray_sort = ascending
52
- systray_icon_size = 24
53
- systray_icon_asb = 100 0 0
54
-
55
97
  task_text = 0
56
98
  task_icon = 1
57
99
  task_centered = 1
58
100
  task_align = center
59
- urgent_nb_of_blink = 8
60
- task_maximum_size = 62 58
61
- task_padding = 10 0
101
+ task_maximum_size = 54 54
102
+ task_padding = 6 6
62
103
  task_tooltip = 1
63
- task_font = Cantarell 10
64
- task_font_color = #c8c8c8 100
65
- task_active_font_color = #ffffff 100
104
+ task_font = General Sans 10
66
105
  task_background_id = 3
67
106
  task_active_background_id = 4
68
107
  task_iconified_background_id = 3
69
108
  task_urgent_background_id = 4
70
109
  task_icon_asb = 100 0 0
71
110
  task_active_icon_asb = 100 0 0
111
+ task_iconified_icon_asb = 55 0 0
112
+ urgent_nb_of_blink = 8
113
+
114
+ separator = new
115
+ separator_background_id = 0
116
+ separator_color = @LINE@ 18
117
+ separator_style = line
118
+ separator_size = 1
119
+ separator_padding = 6 14
72
120
 
73
121
  time1_format = %H:%M
74
- time2_format = %a %b %-d
75
- time1_font = Cantarell bold 11
76
- time2_font = Cantarell 8
77
- clock_font_color = #ffffff 100
78
- clock_padding = 18 0
79
- clock_background_id = 1
122
+ time2_format = %a %-d %b
123
+ time1_font = General Sans Semibold 12
124
+ time2_font = Geist Mono 8
125
+ clock_font_color = @INK@ 100
126
+ clock_padding = 12 0
127
+ clock_background_id = 0
128
+ clock_tooltip = %A, %B %-d
80
129
 
81
- tooltip_padding = 8 6
82
- tooltip_show_timeout = 0.5
130
+ tooltip_padding = 10 6
131
+ tooltip_show_timeout = 0.4
83
132
  tooltip_hide_timeout = 0.1
84
- tooltip_background_id = 1
85
- tooltip_font_color = #ffffff 100
86
- tooltip_font = Cantarell 10
133
+ tooltip_background_id = 5
134
+ tooltip_font_color = @INK@ 100
135
+ tooltip_font = General Sans 10
87
136
 
88
137
  mouse_middle = none
89
138
  mouse_right = close
@@ -0,0 +1,3 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 360 360" fill="#2fc487">
2
+ <path d="M68 30h75v75H68zm75 0h75v75h-75zm75 75h75v75h-75zM68 180h75v75H68zm75 0h75v75h-75zm-75 75h75v75H68zm150 0h75v75h-75z"/>
3
+ </svg>
@@ -0,0 +1,149 @@
1
+ @font-face {
2
+ font-family: "Geist Mono";
3
+ font-style: normal;
4
+ font-weight: 400;
5
+ font-display: swap;
6
+ src: url("./geist-mono-400.ttf") format("truetype");
7
+ }
8
+
9
+ @font-face {
10
+ font-family: "Geist Mono";
11
+ font-style: normal;
12
+ font-weight: 600;
13
+ font-display: swap;
14
+ src: url("./geist-mono-600.ttf") format("truetype");
15
+ }
16
+
17
+ @font-face {
18
+ font-family: "Geist Mono";
19
+ font-style: normal;
20
+ font-weight: 700;
21
+ font-display: swap;
22
+ src: url("./geist-mono-700.ttf") format("truetype");
23
+ }
24
+
25
+ @font-face {
26
+ font-family: "General Sans";
27
+ font-style: normal;
28
+ font-weight: 300;
29
+ font-display: swap;
30
+ src: url("./general-sans-300.ttf") format("truetype");
31
+ }
32
+
33
+ :root {
34
+ --replicas-green: #3eeba3;
35
+ --replicas-glow: rgb(62 235 163 / 7%);
36
+ --replicas-mark-glow: rgb(62 235 163 / 45%);
37
+ --replicas-mark-filter: brightness(1);
38
+ --replicas-surface: #121212;
39
+ --replicas-ink: #ededed;
40
+ --replicas-title: #ffffff;
41
+ --replicas-ink-muted: rgb(255 255 255 / 60%);
42
+ --replicas-ink-faint: rgb(255 255 255 / 40%);
43
+ --replicas-hairline: rgb(255 255 255 / 16%);
44
+ --replicas-hairline-strong: rgb(255 255 255 / 50%);
45
+ --replicas-grid-line: rgb(255 255 255 / 12%);
46
+ --replicas-panel: rgb(18 18 18 / 90%);
47
+ --replicas-grid:
48
+ linear-gradient(to right, var(--replicas-grid-line) 1px, transparent 1px) center / 64px 64px,
49
+ linear-gradient(to bottom, var(--replicas-grid-line) 1px, transparent 1px) center / 64px 64px,
50
+ radial-gradient(circle at 50% 50%, var(--replicas-glow), transparent 36%),
51
+ var(--replicas-surface);
52
+ }
53
+
54
+ :root[data-theme="light"] {
55
+ --replicas-green: #2fc487;
56
+ --replicas-glow: rgb(47 196 135 / 10%);
57
+ --replicas-mark-glow: rgb(47 196 135 / 40%);
58
+ --replicas-mark-filter: brightness(0.84);
59
+ --replicas-surface: #f4f5f1;
60
+ --replicas-ink: #162118;
61
+ --replicas-title: #162118;
62
+ --replicas-ink-muted: rgb(22 33 24 / 60%);
63
+ --replicas-ink-faint: rgb(22 33 24 / 40%);
64
+ --replicas-hairline: rgb(22 33 24 / 14%);
65
+ --replicas-hairline-strong: rgb(22 33 24 / 45%);
66
+ --replicas-grid-line: rgb(22 33 24 / 10%);
67
+ --replicas-panel: rgb(244 245 241 / 92%);
68
+ }
69
+
70
+ html, body {
71
+ width: 100%;
72
+ height: 100%;
73
+ margin: 0;
74
+ overflow: hidden;
75
+ color: var(--replicas-ink);
76
+ font-family: "Geist Mono", ui-monospace, monospace;
77
+ }
78
+
79
+ #status {
80
+ position: fixed;
81
+ inset: 0;
82
+ display: flex;
83
+ flex-direction: column;
84
+ gap: 18px;
85
+ align-items: center;
86
+ justify-content: center;
87
+ pointer-events: none;
88
+ opacity: 0;
89
+ transition: opacity 180ms ease-out;
90
+ }
91
+
92
+ #status.visible { opacity: 1; }
93
+
94
+ #status img {
95
+ width: 56px;
96
+ height: 56px;
97
+ filter: var(--replicas-mark-filter) drop-shadow(0 0 18px var(--replicas-mark-glow));
98
+ animation: status-pulse 2.4s ease-in-out infinite;
99
+ }
100
+
101
+ @keyframes status-pulse {
102
+ 0%, 100% { opacity: 1; }
103
+ 50% { opacity: 0.55; }
104
+ }
105
+
106
+ @media (prefers-reduced-motion: reduce) {
107
+ #status img { animation: none; }
108
+ }
109
+
110
+ #status-title {
111
+ color: var(--replicas-title);
112
+ font-family: "General Sans", system-ui, sans-serif;
113
+ font-size: 30px;
114
+ font-weight: 300;
115
+ letter-spacing: -0.04em;
116
+ line-height: 1;
117
+ }
118
+
119
+ #status-text {
120
+ max-width: 72ch;
121
+ padding: 0 24px;
122
+ color: var(--replicas-ink-muted);
123
+ font-size: 11px;
124
+ font-weight: 600;
125
+ letter-spacing: 0.12em;
126
+ line-height: 1.5;
127
+ text-align: center;
128
+ text-transform: uppercase;
129
+ }
130
+
131
+ .frame-corner, .frame-label {
132
+ position: absolute;
133
+ color: var(--replicas-ink-faint);
134
+ font-size: 14px;
135
+ line-height: 1;
136
+ }
137
+
138
+ .frame-corner:nth-of-type(1) { top: 14px; left: 14px; }
139
+ .frame-corner:nth-of-type(2) { top: 14px; right: 14px; }
140
+ .frame-corner:nth-of-type(3) { bottom: 14px; left: 14px; }
141
+ .frame-corner:nth-of-type(4) { bottom: 14px; right: 14px; }
142
+
143
+ .frame-label {
144
+ top: 16px;
145
+ left: 34px;
146
+ font-size: 10px;
147
+ letter-spacing: 0.14em;
148
+ text-transform: uppercase;
149
+ }
@@ -0,0 +1,8 @@
1
+ (() => {
2
+ const requested = new URLSearchParams(location.search).get('theme');
3
+ const theme = requested === 'light' || requested === 'dark'
4
+ ? requested
5
+ : matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark';
6
+ document.documentElement.dataset.theme = theme;
7
+ document.documentElement.style.colorScheme = theme;
8
+ })();
@@ -1,51 +1,19 @@
1
- @font-face {
2
- font-family: "Geist Mono";
3
- font-style: normal;
4
- font-weight: 400 600;
5
- font-display: swap;
6
- src: url("./geist-mono.woff2") format("woff2");
7
- }
8
-
9
- html, body {
10
- width: 100%;
11
- height: 100%;
12
- margin: 0;
13
- overflow: hidden;
14
- color: rgb(255 255 255 / 72%);
15
- background: radial-gradient(circle at 18% 20%, rgb(62 235 163 / 16%), transparent 34%),
16
- radial-gradient(circle at 84% 78%, rgb(8 44 37 / 85%), transparent 42%),
17
- linear-gradient(135deg, #1b9179 0%, #1d8570 13%, #082b24 100%);
18
- font-family: "Geist Mono", ui-monospace, monospace;
19
- }
1
+ html, body { background: var(--replicas-grid); }
20
2
 
21
3
  #screen { width: 100%; height: 100%; cursor: none; }
22
4
  #screen > div { overflow: hidden !important; background: transparent !important; }
23
5
 
24
- #status {
25
- position: fixed;
26
- inset: 0;
27
- display: flex;
28
- gap: 16px;
29
- align-items: center;
30
- justify-content: center;
31
- pointer-events: none;
32
- opacity: 0;
33
- transition: opacity 240ms ease-out;
34
- }
35
-
36
- #status.visible { opacity: 1; }
37
- #status img { width: 52px; height: 52px; filter: drop-shadow(0 2px 16px rgb(62 235 163 / 50%)); }
38
- #status-text { color: rgb(255 255 255 / 92%); font-size: 24px; font-weight: 500; text-shadow: 0 1px 24px rgb(0 0 0 / 50%); }
6
+ #status { transition-duration: 240ms; }
39
7
 
40
8
  #hint {
41
9
  position: fixed;
42
10
  bottom: 20px;
43
11
  left: 50%;
44
- padding: 7px 12px;
45
- border: 1px solid rgb(255 255 255 / 16%);
46
- color: rgb(255 255 255 / 85%);
47
- background: rgb(13 17 23 / 92%);
48
- font-size: 12px;
12
+ padding: 8px 12px;
13
+ border: 1px solid var(--replicas-hairline);
14
+ color: var(--replicas-ink);
15
+ background: var(--replicas-panel);
16
+ font-size: 11px;
49
17
  font-weight: 500;
50
18
  white-space: nowrap;
51
19
  pointer-events: none;
package/dist/index.js CHANGED
@@ -31,6 +31,7 @@ var STREAM_PORT = process.env.REPLICAS_DESKTOP_STREAM_PORT ? parseInt(process.en
31
31
  var SERVICES_SCRIPT = process.env.REPLICAS_COMPUTER_SERVICES_SCRIPT || "/usr/local/bin/replicas-start-desktop-services";
32
32
  var INPUT_LOCK_FILE = process.env.REPLICAS_DESKTOP_INPUT_LOCK_FILE || `${STATE_DIR}/input.lock`;
33
33
  var CHROME_WRAPPER = "/usr/local/bin/replicas-chrome";
34
+ var TERMINAL_WRAPPER = "/usr/local/bin/replicas-terminal";
34
35
  var INFO_WAIT_TIMEOUT_MS = 1e4;
35
36
  var INFO_WAIT_INTERVAL_MS = 500;
36
37
  var lastDesktopHealthAt = 0;
@@ -2673,7 +2674,7 @@ var APP_ALIASES = {
2673
2674
  chrome: [CHROME_WRAPPER],
2674
2675
  chromium: ["chromium", "--no-first-run", "--no-default-browser-check"],
2675
2676
  firefox: ["firefox"],
2676
- terminal: ["xfce4-terminal"],
2677
+ terminal: [TERMINAL_WRAPPER],
2677
2678
  xterm: ["xterm"],
2678
2679
  notepad: ["mousepad"],
2679
2680
  editor: ["mousepad"],
@@ -2925,7 +2926,7 @@ async function computerStatusCommand() {
2925
2926
  }
2926
2927
 
2927
2928
  // src/version.ts
2928
- var COMPUTER_USE_VERSION = "0.2.9";
2929
+ var COMPUTER_USE_VERSION = "0.2.11";
2929
2930
  var COMPUTER_USE_PROTOCOL_VERSION = 1;
2930
2931
 
2931
2932
  // src/program.ts
@@ -3543,6 +3544,7 @@ function mediaPacket(kind, timestamp, payload) {
3543
3544
  function validInput(value) {
3544
3545
  if (!value || typeof value !== "object" || !("type" in value) || typeof value.type !== "string") return false;
3545
3546
  if (value.type === "release") return true;
3547
+ if (value.type === "theme") return "theme" in value && (value.theme === "light" || value.theme === "dark");
3546
3548
  if (value.type === "stats") return "videoFps" in value && typeof value.videoFps === "number" && Number.isFinite(value.videoFps) && "audioPacketsPerSecond" in value && typeof value.audioPacketsPerSecond === "number" && Number.isFinite(value.audioPacketsPerSecond) && "decodeQueue" in value && typeof value.decodeQueue === "number" && Number.isFinite(value.decodeQueue) && "rttMs" in value && typeof value.rttMs === "number" && Number.isFinite(value.rttMs);
3547
3549
  if (value.type === "ping" || value.type === "pong") return "sentAt" in value && typeof value.sentAt === "number";
3548
3550
  if (value.type === "key") return "code" in value && typeof value.code === "string" && value.code.length < 40 && "down" in value && typeof value.down === "boolean";
@@ -3551,6 +3553,28 @@ function validInput(value) {
3551
3553
  if (value.type === "button") return "button" in value && typeof value.button === "number" && "down" in value && typeof value.down === "boolean";
3552
3554
  return value.type === "wheel" && "deltaX" in value && typeof value.deltaX === "number" && "deltaY" in value && typeof value.deltaY === "number";
3553
3555
  }
3556
+ var appliedTheme;
3557
+ var pendingTheme;
3558
+ var applyingTheme = false;
3559
+ function applyDesktopTheme(theme) {
3560
+ pendingTheme = theme;
3561
+ if (!applyingTheme) drainDesktopTheme();
3562
+ }
3563
+ function drainDesktopTheme() {
3564
+ const theme = pendingTheme;
3565
+ pendingTheme = void 0;
3566
+ if (theme === void 0 || theme === appliedTheme) return;
3567
+ applyingTheme = true;
3568
+ const finish = (applied) => {
3569
+ applyingTheme = false;
3570
+ if (applied) appliedTheme = theme;
3571
+ drainDesktopTheme();
3572
+ };
3573
+ const child = spawn4("bash", [SERVICES_SCRIPT, "--theme", theme], { detached: true, stdio: "ignore" });
3574
+ child.unref();
3575
+ child.once("exit", (code) => finish(code === 0));
3576
+ child.once("error", () => finish(false));
3577
+ }
3554
3578
  async function runMediaServer() {
3555
3579
  if (![width, height, fps, port].every((value) => Number.isInteger(value) && value > 0)) throw new Error("Invalid desktop stream dimensions, frame rate, or port");
3556
3580
  const videoSocket = await bindUdp();
@@ -3925,7 +3949,8 @@ async function runMediaServer() {
3925
3949
  decodeQueue: clamp(message.decodeQueue, 0, 1e3),
3926
3950
  rttMs: clamp(message.rttMs, 0, 6e5)
3927
3951
  };
3928
- } else clients.get(client)?.input.handle(message);
3952
+ } else if (message.type === "theme") applyDesktopTheme(message.theme);
3953
+ else clients.get(client)?.input.handle(message);
3929
3954
  });
3930
3955
  client.once("close", () => {
3931
3956
  clients.get(client)?.input.close();
@@ -3972,7 +3997,7 @@ async function runMediaServer() {
3972
3997
 
3973
3998
  // src/setup.ts
3974
3999
  import { spawnSync as spawnSync6 } from "child_process";
3975
- import { accessSync, chmodSync as chmodSync2, constants, cpSync, existsSync as existsSync7, mkdirSync as mkdirSync6, writeFileSync as writeFileSync5 } from "fs";
4000
+ import { accessSync, chmodSync as chmodSync2, constants, cpSync, existsSync as existsSync7, mkdirSync as mkdirSync6, readdirSync, writeFileSync as writeFileSync5 } from "fs";
3976
4001
  import { dirname as dirname7, resolve as resolve3 } from "path";
3977
4002
  import { fileURLToPath as fileURLToPath2 } from "url";
3978
4003
  var dependencies = [
@@ -4000,6 +4025,7 @@ var dependencies = [
4000
4025
  ["sudo", "sudo"],
4001
4026
  ["systemctl", "systemctl"],
4002
4027
  ["hsetroot", "hsetroot"],
4028
+ ["fontconfig", "fc-cache"],
4003
4029
  ["XFCE terminal", "xfce4-terminal"],
4004
4030
  ["Mousepad", "mousepad"],
4005
4031
  ["Thunar", "thunar"]
@@ -4083,25 +4109,31 @@ function setupComputer(options = {}) {
4083
4109
  if (!existsSync7(assets)) throw new Error(`Computer-use assets are missing from ${assets}`);
4084
4110
  mkdirSync6("/usr/local/share/replicas/desktop", { recursive: true });
4085
4111
  cpSync(assets, "/usr/local/share/replicas/desktop", { recursive: true, force: true });
4112
+ const fontRoot = "/usr/local/share/fonts/replicas";
4113
+ mkdirSync6(fontRoot, { recursive: true });
4114
+ for (const file of readdirSync(assets).filter((name) => name.endsWith(".ttf"))) cpSync(resolve3(assets, file), resolve3(fontRoot, file), { force: true });
4115
+ spawnSync6("fc-cache", ["-f", fontRoot], { stdio: "ignore" });
4086
4116
  const viewerRoot = "/usr/local/share/replicas/desktop/novnc";
4087
4117
  mkdirSync6(viewerRoot, { recursive: true });
4088
4118
  cpSync(noVncCore, resolve3(viewerRoot, "core"), { recursive: true, force: true });
4089
4119
  cpSync(noVncVendor, resolve3(viewerRoot, "vendor"), { recursive: true, force: true });
4090
- for (const file of ["novnc-index.html", "viewer.css", "viewer-icon.svg", "geist-mono.woff2"]) {
4120
+ for (const file of ["novnc-index.html", "viewer.css", "viewer-theme.css", "viewer-theme.js", "viewer-icon.svg", "geist-mono-400.ttf", "geist-mono-600.ttf", "geist-mono-700.ttf", "general-sans-300.ttf"]) {
4091
4121
  cpSync(resolve3(assets, file), resolve3(viewerRoot, file === "novnc-index.html" ? "index.html" : file), { force: true });
4092
4122
  }
4093
4123
  cpSync(resolve3(packageRoot2, "dist", "viewer.js"), resolve3(viewerRoot, "viewer.js"), { force: true });
4094
4124
  const streamRoot = "/usr/local/share/replicas/desktop/stream";
4095
4125
  mkdirSync6(streamRoot, { recursive: true });
4096
- for (const file of ["stream-index.html", "stream-viewer.css", "viewer-icon.svg", "geist-mono.woff2"]) {
4126
+ for (const file of ["stream-index.html", "stream-viewer.css", "viewer-theme.css", "viewer-theme.js", "viewer-icon.svg", "geist-mono-400.ttf", "geist-mono-600.ttf", "geist-mono-700.ttf", "general-sans-300.ttf"]) {
4097
4127
  cpSync(resolve3(assets, file), resolve3(streamRoot, file), { force: true });
4098
4128
  }
4099
4129
  cpSync(resolve3(packageRoot2, "dist", "stream-viewer.js"), resolve3(streamRoot, "stream-viewer.js"), { force: true });
4100
4130
  cpSync(resolve3(assets, "start-services.sh"), "/usr/local/bin/replicas-start-desktop-services", { force: true });
4101
4131
  cpSync(resolve3(assets, "replicas-chrome"), "/usr/local/bin/replicas-chrome", { force: true });
4132
+ cpSync(resolve3(assets, "replicas-terminal"), "/usr/local/bin/replicas-terminal", { force: true });
4102
4133
  cpSync(resolve3(assets, "replicas-chrome.desktop"), "/usr/share/applications/replicas-chrome.desktop", { force: true });
4103
4134
  chmodSync2("/usr/local/bin/replicas-start-desktop-services", 493);
4104
4135
  chmodSync2("/usr/local/bin/replicas-chrome", 493);
4136
+ chmodSync2("/usr/local/bin/replicas-terminal", 493);
4105
4137
  writeFileSync5("/etc/systemd/system/replicas-computer.service", serviceUnit, { mode: 420 });
4106
4138
  if (existsSync7("/run/systemd/system")) {
4107
4139
  const reload = spawnSync6("systemctl", ["daemon-reload"], { stdio: "pipe" });
@@ -192,6 +192,7 @@ var connect = () => {
192
192
  nextSocket.addEventListener("open", () => {
193
193
  if (socket !== nextSocket) return;
194
194
  reconnectAttempt = 0;
195
+ send({ type: "theme", theme: document.documentElement.dataset.theme === "light" ? "light" : "dark" });
195
196
  });
196
197
  nextSocket.addEventListener("message", (event) => {
197
198
  if (socket !== nextSocket) return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "replicas-computer",
3
- "version": "0.2.9",
3
+ "version": "0.2.11",
4
4
  "description": "Replicas workspace computer-use runtime",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
Binary file