Protothreads revolve around the concept of local continuations. Unlike traditional continuations, a local continuation only captures the state of execution within the local function in which they are created. I.e., a local continuation does not contain the call stack. This makes it possible to do things like invoking protothreads from multiple call paths.
The "hack" you refer to is just one possible implementation of the protothread concept, in which the local continuations are implemented by a switch statement in the spirit of Duff's device. This implementation technique allows the protothreads library to be implemented in only 7 lines of code (!) but it has a bunch of drawbacks, such as not recording the state of local variables. In fact, because of these drawbacks, the switch-based implementation arguably does not provide a fully functional version of protothreads.
There are other ways to implement protothreads. The original protothreads library contains an implementation where the local continuations are done using gotos and gcc's labels-as-values feature. This does remove some of the problems with the switch statement, but still does not record local variables. Others have implemented protothreads in C++, where a class object is used to store local variables, and by adding a C2C wrapper compiler that produces C code that stores and restores the local variables.
Protothreads were created to explore some of the finer points in the twilight zone between multithreading/coroutines and events/state machines. The intent was never to emulate continuations, coroutines, or threads but to find a less expensive way to achieve linear code flow. With protothreads, linear code flow can be achieved without having to store multiple thread stacks, which is important in many of the systems for which protothreads were originally intended. The switch-based implementation also has the added benefit of being possible use with any C compiler, which has been very useful as we have ported Contiki to a bunch of different platforms and C compilers.
But, yeah, the switch-based implementation of the protothreads concept can definitely be labelled as a hack. But - admit it - a beautiful hack! :)