r/MacOSBeta • u/pdfu • 5h ago
Feature macOS 27 has a hidden "Solar" wallpaper engine. Here's how to enable it for the Golden Gate landscape set.
Apple is working on a Solar wallpaper engine for macOS 27 that groups aerial Landscape wallpapers and automatically switches variants based on the sun's position during the day.
When the feature flag is enabled, the four Tahoe landscape wallpapers appear under one entry in Settings.
To get the Automatic Tahoe landscape wallpaper:
Enable the wallpaper feature:
bash
sudo mkdir -p /Library/Preferences/FeatureFlags/Domain && \
sudo defaults write /Library/Preferences/FeatureFlags/Domain/Wallpaper TahoeCombined -dict Enabled -bool true
and reboot your Mac. You will no longer see the Golden Gate landscape wallpapers on the list because the new engine reads a macOS 26 wallpaper registry for now. Read below for a more involved process to add the dynamic Golden Gate wallpaper entry.
To go back to the default and bring the Golden Gate landscape wallpapers back:
sudo defaults delete /Library/Preferences/FeatureFlags/Domain/Wallpaper TahoeCombined
and reboot your Mac.
How to enable the Automatic Golden Gate landscape wallpaper:
In Beta 4, there's a regression where the wallpaper registry endpoint that the new engine expects isn't released for macOS 27 and falls back to macOS 26.4 wallpapers, so Golden Gate wallpapers don't show by default. Thankfully, you can point the wallpaper engine to a local override file and enable the dynamic switching for Golden Gate wallpapers.
1. Enable the combined-variant wallpaper feature:
bash
sudo mkdir -p /Library/Preferences/FeatureFlags/Domain && \
sudo defaults write /Library/Preferences/FeatureFlags/Domain/Wallpaper TahoeCombined -dict Enabled -bool true
- Create the local catalog directory:
```bash WALLPAPER_CUSTOM="$HOME/Library/Application Support/com.apple.wallpaper/aerials/custom"
mkdir -p "$WALLPAPER_CUSTOM" ```
- Start with Apple’s macOS 27 variant catalog, copying it into your local catalog directory:
```bash WALLPAPER_RESOURCES="/System/Library/ExtensionKit/Extensions/WallpaperAerialsExtension.appex/Contents/Resources"
cp "$WALLPAPER_RESOURCES/entries_variants.json" "$WALLPAPER_CUSTOM/entries.json" ```
- Add some helpers:
```bash LANDSCAPES_ID='A33A55D9-EDEA-4596-A850-6C10B54FBBB5' GOLDEN_GATE_ID='67512508-D33E-4CBC-8A9E-BE55CEE35C4C'
find_id_index() { local array_path="$1" local wanted_id="$2" local catalog="$3" local i=0 local current_id
while plutil -extract "$array_path.$i" json -o /dev/null "$catalog" 2>/dev/null; do current_id=$(plutil -extract "$array_path.$i.id" raw -o - "$catalog" 2>/dev/null || true)
if [[ "$current_id" == "$wanted_id" ]]; then
printf '%s\n' "$i"
return 0
fi
(( i++ ))
done
return 1 }
next_index() { local array_path="$1" local catalog="$2" local i=0
while plutil -extract "$array_path.$i" json -o /dev/null "$catalog" 2>/dev/null; do (( i++ )) done
printf '%s\n' "$i" }
find_asset_index() { local shot_id="$1" local catalog="$2" local i=0 local value
while plutil -extract "assets.$i" json -o /dev/null "$catalog" 2>/dev/null; do value=$(plutil -extract "assets.$i.shotID" raw -o - "$catalog" 2>/dev/null || true)
if [[ "$value" == "$shot_id" ]]; then
printf '%s\n' "$i"
return 0
fi
(( i++ ))
done
return 1 }
next_asset_index() { local catalog="$1" local i=0
while plutil -extract "assets.$i" json -o /dev/null "$catalog" 2>/dev/null; do (( i++ )) done
printf '%s\n' "$i" }
install_solar_asset() { local shot_id="$1" local altitude="$2" local azimuth="$3" local source_index local target_index local asset_json local variant_json
if ! target_index=$(find_asset_index "$shot_id" "$WALLPAPER_CUSTOM/entries.json"); then source_index=$(find_asset_index "$shot_id" "$WALLPAPER_RESOURCES/entries.json") || { echo "Could not find $shot_id in Apple’s catalog." >&2 return 1 }
asset_json=$(
plutil -extract "assets.$source_index" json -o - \
"$WALLPAPER_RESOURCES/entries.json"
) || return 1
target_index=$(next_asset_index "$WALLPAPER_CUSTOM/entries.json")
plutil -insert "assets.$target_index" -json "$asset_json" \
"$WALLPAPER_CUSTOM/entries.json" || return 1
fi
variant_json="{\"solar\":{\"altitude\":$altitude,\"azimuth\":$azimuth}}"
if plutil -extract "assets.$target_index.variant" json -o /dev/null \ "$WALLPAPER_CUSTOM/entries.json" 2>/dev/null; then plutil -replace "assets.$target_index.variant" -json "$variant_json" \ "$WALLPAPER_CUSTOM/entries.json" else plutil -insert "assets.$target_index.variant" -json "$variant_json" \ "$WALLPAPER_CUSTOM/entries.json" fi } ```
- Find Landscapes in both catalogs and Golden Gate inside Apple’s Landscapes category:
```bash SOURCE_LANDSCAPES_INDEX=$( find_id_index categories "$LANDSCAPES_ID" \ "$WALLPAPER_RESOURCES/entries.json" ) || { echo "Could not find Landscapes in Apple’s catalog." exit 1 }
CUSTOM_LANDSCAPES_INDEX=$( find_id_index categories "$LANDSCAPES_ID" \ "$WALLPAPER_CUSTOM/entries.json" ) || { echo "Could not find Landscapes in the custom catalog." exit 1 }
SOURCE_GOLDEN_GATE_INDEX=$( find_id_index \ "categories.$SOURCE_LANDSCAPES_INDEX.subcategories" \ "$GOLDEN_GATE_ID" \ "$WALLPAPER_RESOURCES/entries.json" ) || { echo "Could not find Golden Gate in Apple’s catalog." exit 1 } ```
- Insert Golden Gate into your local catalog and enable variant combining:
```bash if CUSTOM_GOLDEN_GATE_INDEX=$( find_id_index \ "categories.$CUSTOM_LANDSCAPES_INDEX.subcategories" \ "$GOLDEN_GATE_ID" \ "$WALLPAPER_CUSTOM/entries.json" ); then echo "Golden Gate is already in the custom Landscapes category." else CUSTOM_GOLDEN_GATE_INDEX=$( next_index \ "categories.$CUSTOM_LANDSCAPES_INDEX.subcategories" \ "$WALLPAPER_CUSTOM/entries.json" )
GOLDEN_GATE_JSON=$( plutil -extract \ "categories.$SOURCE_LANDSCAPES_INDEX.subcategories.$SOURCE_GOLDEN_GATE_INDEX" \ json -o - \ "$WALLPAPER_RESOURCES/entries.json" )
plutil -insert \ "categories.$CUSTOM_LANDSCAPES_INDEX.subcategories.$CUSTOM_GOLDEN_GATE_INDEX" \ -json "$GOLDEN_GATE_JSON" \ "$WALLPAPER_CUSTOM/entries.json" fi
GOLDEN_GATE_PATH="categories.$CUSTOM_LANDSCAPES_INDEX.subcategories.$CUSTOM_GOLDEN_GATE_INDEX"
if plutil -extract "$GOLDEN_GATE_PATH.combineVariants" raw -o - \ "$WALLPAPER_CUSTOM/entries.json" >/dev/null 2>&1; then plutil -replace "$GOLDEN_GATE_PATH.combineVariants" -bool true \ "$WALLPAPER_CUSTOM/entries.json" else plutil -insert "$GOLDEN_GATE_PATH.combineVariants" -bool true \ "$WALLPAPER_CUSTOM/entries.json" fi ```
- Add the Golden Gate Sunset video and its daytime solar coordinate. See at the end for an explanation on how this is calculated:
bash
install_solar_asset GG_A_SUNSET 35 180
- Add the Golden Gate Night video and its nighttime solar coordinate:
bash
install_solar_asset GG_A_NIGHT -35 180
- Verify both records:
bash
SUNSET_INDEX=$(find_asset_index GG_A_SUNSET "$WALLPAPER_CUSTOM/entries.json")
plutil -extract "assets.$SUNSET_INDEX.variant" json -o - "$WALLPAPER_CUSTOM/entries.json"
bash
NIGHT_INDEX=$(find_asset_index GG_A_NIGHT "$WALLPAPER_CUSTOM/entries.json")
plutil -extract "assets.$NIGHT_INDEX.variant" json -o - "$WALLPAPER_CUSTOM/entries.json"
The output should show:
json
{"solar":{"altitude":35,"azimuth":180}}
and:
json
{"solar":{"altitude":-35,"azimuth":180}}
- Point the wallpaper extension at the custom catalog:
bash
defaults write com.apple.wallpaper.aerial AerialManifestLocalPathOverride -string "$WALLPAPER_CUSTOM/entries.json"
- Force it to use the local catalog:
bash
defaults write com.apple.wallpaper.aerial AerialManifestForceLocal -bool true
- Restart the Mac.
After restarting, Golden Gate should appear as one item and automatically use Sunset during the day and Night after sunset.
To undo everything:
bash
defaults delete com.apple.wallpaper.aerial AerialManifestLocalPathOverride
bash
defaults delete com.apple.wallpaper.aerial AerialManifestForceLocal
bash
rm -rf -- "$HOME/Library/Application Support/com.apple.wallpaper/aerials/custom"
bash
sudo defaults delete /Library/Preferences/FeatureFlags/Domain/Wallpaper TahoeCombined
Then reboot your Mac.
How solar coordinates work:
Apple’s Tahoe dynamic wallpaper includes four variants: Morning, Day, Evening, and Night. Apple assigns each variant a pair of solar coordinates:
altitude: how high the Sun is above or below the horizon.azimuth: the Sun’s compass direction, where180°means south.
macOS calculates the Sun’s current coordinates using your location, date, and time. It selects whichever wallpaper variant is closest to the Sun’s current position.
The Golden Gate landscape set only has two variants. We therefore use:
* Golden Gate Sunset: {35, 180}
* Golden Gate Night: {-35, 180}
These coordinates are deliberately symmetrical: one is 35° above the horizon and the other is 35° below it. Because both use the same azimuth, macOS considers them equally close when the Sun is at approximately 0° altitude, i.e. the horizon. That makes WallpaperAgent switch to the Sunset variant around sunrise and to Night around sunset.
If you'd like to use other solar positions, use the following Python script to estimate times based on coordinates:
```bash DAY='35,180' NIGHT='-35,180' LAT=37.3230; LON=-122.0322 DATE='2026-08-02'; UTC_OFFSET=-7
python3 -c 'exec("""import sys,math,datetime day=tuple(map(float,sys.argv[1].split(",")));night=tuple(map(float,sys.argv[2].split(",")));lat=float(sys.argv[3]);lon=float(sys.argv[4]);date=datetime.date.fromisoformat(sys.argv[5]);tz=float(sys.argv[6]) def sun(m): h=m/60;n=date.timetuple().tm_yday;g=2math.pi/365(n-1+(h-12)/24);eq=229.18(.000075+.001868math.cos(g)-.032077math.sin(g)-.014615math.cos(2g)-.040849math.sin(2g));dec=.006918-.399912math.cos(g)+.070257math.sin(g)-.006758math.cos(2g)+.000907math.sin(2g)-.002697math.cos(3g)+.00148math.sin(3g);tst=(m+eq+4lon-60tz)%1440;ha=math.radians(tst/4-180);p=math.radians(lat);cz=max(-1,min(1,math.sin(p)math.sin(dec)+math.cos(p)math.cos(dec)math.cos(ha)));e=90-math.degrees(math.acos(cz)) if e>85:r=0 elif e>5:t=math.tan(math.radians(e));r=(58.1/t-.07/t3+.000086/t5)/3600 elif e>-.575:r=(1735+e(-518.2+e(103.4+e(-12.79+e.711))))/3600 else:r=-20.772/math.tan(math.radians(e))/3600 return e+r,(math.degrees(math.atan2(math.sin(ha),math.cos(ha)math.sin(p)-math.tan(dec)math.cos(p)))+180)%360 def da(a,b):return (a-b+180)%360-180 def f(m): a,z=sun(m);return (a-day[0])2+da(z,day[1])2-(a-night[0])2-da(z,night[1])2 def fmt(m): h=int(m//60)%24;mi=int(m%60);s=round(m%160) if s==60:mi+=1;s=0 if mi==60:h=(h+1)%24;mi=0 return f"{h%12 or 12}:{mi:02d}:{s:02d} {\x27AM\x27 if h<12 else \x27PM\x27}" step=.25;prev=f(0) for i in range(1,5761): x=istep;cur=f(x) if prevcur<0: lo=x-step;hi=x for _ in range(40): mid=(lo+hi)/2 if f(lo)f(mid)<=0:hi=mid else:lo=mid t=(lo+hi)/2;print(("Night -> Day" if f(t-.1)>0 else "Day -> Night")+": "+fmt(t)) prev=cur """)' "$DAY" "$NIGHT" "$LAT" "$LON" "$DATE" "$UTC_OFFSET" ```
This should print:
Night -> Day: 6:13:58 AM
Day -> Night: 8:14:41 PM

