// Update is called once per frame
    void FixedUpdate()
    {
        // monitor for engine start (not ideal, but avoids linking to LaunchUI script)
        if ((timeStarted < 0) && engine.engineOn)
        {
            timeStarted = ge.GetPhysicalTime();
            float   pitch0        = pitchCurve.Evaluate(0);
            Vector3 localVertical = Vector3.Normalize(ge.GetPhysicsPosition(ship) - ge.GetPhysicsPosition(earth));
            lastAttitude = Vector3.Cross(localVertical, Vector3.forward); // forward = (0,0,1)
            lastAttitude = Quaternion.AngleAxis(pitch0, Vector3.forward) * lastAttitude;
        }

        if (timeStarted > 0)
        {
            float t = (float)(ge.GetTimeWorldSeconds() - timeStarted) / timeRangePhysical;
            t = Mathf.Clamp(t, 0f, 1f);

            // pitch in range 0..90 as curve goes 0..1
            float pitch = pitchCurve.Evaluate(t) * 90.0f;
            // find the local vertical
            Vector3 localVertical = Vector3.Normalize(ge.GetPhysicsPosition(ship) - ge.GetPhysicsPosition(earth));
            // First get local horizontal (this ordering of cross product assumes we want to go East)
            Vector3 attitude = Vector3.Cross(localVertical, Vector3.forward); // forward = (0,0,1)
            attitude = Quaternion.AngleAxis(pitch, Vector3.forward) * attitude;
            engine.SetThrustAxis(-attitude);
            shipModel.RotateToVector(attitude);

            // when attitude changes by 1 degree, re-compute trajectories
            if (Vector3.Angle(attitude, lastAttitude) > 1f)
            {
                ge.TrajectoryRestart();
                lastAttitude = attitude;
            }

            // thrust
            float thrust = thrustCurve.Evaluate(t);
            engine.SetThrottlePercent(100f * thrust);
        }
    }