/ de-omarchy / bin / omarchy-capture-webcam-resize
swadhinbiswas Initial de-omarchy: Omarchy UI layer for Arch-based distros · 8/22/2026
9f393b2
150 lines · 4.8 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
#!/bin/bash

# omarchy:summary=Resize the active webcam recording overlay
# omarchy:group=capture
# omarchy:args=<smaller|larger|reset|small|medium|large>
# omarchy:examples=omarchy capture webcam resize smaller | omarchy-capture-webcam-resize reset

set -euo pipefail

readonly MARGIN=40
readonly REGION_FILE="${XDG_RUNTIME_DIR:-/tmp}/omarchy-screenrecord-region"

usage() {
  echo "Usage: omarchy-capture-webcam-resize <smaller|larger|reset|small|medium|large>" >&2
  exit 1
}

hypr_dispatch() {
  local lua="$1"
  shift

  hyprctl dispatch "$lua" >/dev/null 2>&1 || hyprctl dispatch "$@" >/dev/null
}

action=${1:-}
case $action in
smaller | larger | reset | small | medium | large) ;;
*) usage ;;
esac

if ! client=$(hyprctl clients -j 2>/dev/null | jq -cer 'first(.[] | select(.title == "WebcamOverlay")) // empty' 2>/dev/null); then
  exit 0
fi

read -r address current_width current_height monitor_id < <(
  jq -r '[.address, .size[0], .size[1], .monitor] | @tsv' <<<"$client"
)

[[ -n $address && $current_width =~ ^[0-9]+$ && $current_height =~ ^[0-9]+$ && $monitor_id =~ ^[0-9]+$ ]] || exit 0
((current_width > 0 && current_height > 0)) || exit 0

if ! monitor=$(hyprctl monitors -j 2>/dev/null | jq -cer --argjson id "$monitor_id" 'first(.[] | select(.id == $id)) // empty' 2>/dev/null); then
  exit 0
fi

read -r monitor_x monitor_y monitor_width monitor_height < <(
  jq -r '
    . as $monitor |
    (($monitor.transform // 0) % 2 == 1) as $rotated |
    [
      .x,
      .y,
      (((if $rotated then .height else .width end) / .scale) | floor),
      (((if $rotated then .width else .height end) / .scale) | floor)
    ] | @tsv
  ' <<<"$monitor"
)

[[ $monitor_x =~ ^-?[0-9]+$ && $monitor_y =~ ^-?[0-9]+$ && $monitor_width =~ ^[0-9]+$ && $monitor_height =~ ^[0-9]+$ ]] || exit 0

# Anchor to the recorded region when there is one, so a window picked on a wide
# display keeps the camera in its own corner. Full-monitor captures, the portal
# backend, and resizes outside a recording publish none and fall back here.
anchor_x=$monitor_x
anchor_y=$monitor_y
anchor_width=$monitor_width
anchor_height=$monitor_height

if [[ -f $REGION_FILE ]] && region=$(<"$REGION_FILE"); then
  if [[ $region =~ ^([0-9]+)x([0-9]+)\+(-?[0-9]+)\+(-?[0-9]+)$ ]]; then
    anchor_width=${BASH_REMATCH[1]}
    anchor_height=${BASH_REMATCH[2]}
    anchor_x=${BASH_REMATCH[3]}
    anchor_y=${BASH_REMATCH[4]}
  fi
fi

# A tall, narrow region can't fit presets scaled from its own height, so cap the
# height they scale from to what the width allows — the large preset is the
# widest at 3/10 of it. Scaling the ladder as a whole leaves small, medium and
# large distinct sizes for smaller and larger to step between.
scale_height=$anchor_height
available_width=$((anchor_width - 2 * MARGIN))
((available_width > 0 && scale_height * 3 / 10 > available_width)) &&
  scale_height=$((available_width * 10 / 3))

# Scale the 8:9 portrait presets from that height so they occupy the same
# proportion of a 1080p, HiDPI, ultrawide, or 6K recording.
small_height=$(((scale_height * 9 + 25) / 50))
small_width=$(((small_height * 8 + 4) / 9))
medium_height=$(((scale_height + 2) / 4))
medium_width=$(((medium_height * 8 + 4) / 9))
large_height=$(((scale_height * 27 + 40) / 80))
large_width=$(((large_height * 8 + 4) / 9))

target_width=$current_width
target_height=$current_height
case $action in
small)
  target_width=$small_width
  target_height=$small_height
  ;;
medium | reset)
  target_width=$medium_width
  target_height=$medium_height
  ;;
large)
  target_width=$large_width
  target_height=$large_height
  ;;
smaller)
  if ((large_width < current_width)); then
    target_width=$large_width
    target_height=$large_height
  elif ((medium_width < current_width)); then
    target_width=$medium_width
    target_height=$medium_height
  elif ((small_width < current_width)); then
    target_width=$small_width
    target_height=$small_height
  fi
  ;;
larger)
  if ((small_width > current_width)); then
    target_width=$small_width
    target_height=$small_height
  elif ((medium_width > current_width)); then
    target_width=$medium_width
    target_height=$medium_height
  elif ((large_width > current_width)); then
    target_width=$large_width
    target_height=$large_height
  fi
  ;;
esac

target_x=$((anchor_x + anchor_width - target_width - MARGIN))
target_y=$((anchor_y + anchor_height - target_height - MARGIN))

((target_x < anchor_x + MARGIN)) && target_x=$((anchor_x + MARGIN))
((target_y < anchor_y + MARGIN)) && target_y=$((anchor_y + MARGIN))

window="address:$address"
hypr_dispatch \
  "hl.dsp.window.resize({ window = \"$window\", x = $target_width, y = $target_height })" \
  resizewindowpixel "exact $target_width $target_height,$window"
hypr_dispatch \
  "hl.dsp.window.move({ window = \"$window\", x = $target_x, y = $target_y })" \
  movewindowpixel "exact $target_x $target_y,$window"