Good news that it worked! This new idea could work but in this case likely has some issues. Pwm works by changing the ratio of on time to off time and the relays are likely not fast enough to react quickly enough to do that. If you replace the relays with motor drivers or an output driver of some other type that are fast enough to support pwm that should work fine. You may need to opto isolate the outputs to keep the isolation that the relays are currently providing if you need that. You likely don’t want to use the output enable however because it switches from active drive (high or low) to no drive which leaves the output floating and cmos inputs (motor drivers and many other drivers these days) don’t like floating inputs, they want either high or low with a fast transition between the two states. Unl2003 Darlington transistor drivers should be happy enough with the output drive from the shift registers though (they aren’t bothered by the lack of active pull up or pull down like a cmos input is) . You might be better to do the pwm on the input side of the shift registers by alternating shifting all 0s into the registers with shifting the values for the leds in to the registers which uses the active outputs from the shift register to drive the input to the electronic driver at high speed. You have to add code to start from always shift the data from Vixen to the shift registers (as now) to alternating shifting the Vixen data and all 0s. The fade is arranged by (using a simple 4 bit example, scale to higher numbers for a smoother fade) start with every bit time being the Vixen data, next 3 time periods of Vixen data and one time period of 0 (somewhat dimmer) then 2 time periods of Vixen data and 2 time periods of 0s (dimmer again) then 3 time periods of 0 and 1 time period of Vixen data (dimmest) then all time periods of 0 (off). That is essentially what the pwm is doing in hardware but it can be done as software too.
Peter