     advanceFrame(_actionIndex == _idleAction);
   }
 
-  const auto& frame = kActions[_actionIndex].frames[_frameIndex];
+  auto& frame = kActions[_actionIndex].frames[_frameIndex];
 
-  for (int servoIndex = 0; servoIndex < kServoCenter.size(); servoIndex++)
+  for (int servoIndex = 0; servoIndex < kServoSpecs.size(); servoIndex++)
   {
-    int pulseLen = (float(frame.boneAngles[servoIndex]) / 360) * (kServoMax - kServoMin) + kServoMin;
+    auto& servoConfig = kServoSpecs[servoIndex];
+    auto& spec = servoConfig.spec;
+    float angle = frame.boneAngles[servoIndex] + servoConfig.center;
+    angle = servoConfig.flip ? (180 - angle) : angle;
+    int pulseLen = (angle / 180) * (spec.pulseMax - spec.pulseMin) + spec.pulseMin;
     _servoMux.setPWM(servoIndex, 0, pulseLen);
   }
 

  _frameIndex = 0;
  _frameCount = kActions[_actionIndex].frames.size();
  _lastFrameMillis = millis();
  
  serialPrintfln("starting animation %s (%d frames)", kActions[_actionIndex].name, kActions[_actionIndex].frames.size());
}


int _frameIndex = 0;
int _frameCount = 1;
int _lastFrameMillis = 0;
  
void setup()
{
  Serial.begin(115200);
