diff --git a/src/mol-plugin/state/animation/manager.ts b/src/mol-plugin/state/animation/manager.ts
new file mode 100644
index 0000000000000000000000000000000000000000..a1c5ab5b563a9978dc3ad6f9f3e7d325ab3bfa4b
--- /dev/null
+++ b/src/mol-plugin/state/animation/manager.ts
@@ -0,0 +1,7 @@
+/**
+ * Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author David Sehnal <david.sehnal@gmail.com>
+ */
+
+// TODO
\ No newline at end of file
diff --git a/src/mol-plugin/state/animation/model.ts b/src/mol-plugin/state/animation/model.ts
new file mode 100644
index 0000000000000000000000000000000000000000..132663887a6c7287810562bbf82e0ac270286754
--- /dev/null
+++ b/src/mol-plugin/state/animation/model.ts
@@ -0,0 +1,37 @@
+/**
+ * Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
+ *
+ * @author David Sehnal <david.sehnal@gmail.com>
+ */
+
+import { ParamDefinition as PD } from 'mol-util/param-definition';
+import { PluginContext } from 'mol-plugin/context';
+
+export { PluginStateAnimation }
+
+interface PluginStateAnimation<P extends PD.Params, S> {
+    id: string,
+    params: (ctx: PluginContext) => P,
+    initialState(params: PD.Values<P>, ctx: PluginContext): S,
+
+    /**
+     * Apply the current frame and modify the state.
+     * @param t Current absolute time since the animation started.
+     */
+    apply(state: S, t: number, ctx: PluginStateAnimation.Context<P>): Promise<PluginStateAnimation.ApplyResult<S>>,
+
+    /**
+     * The state must be serializable to JSON. If JSON.stringify is not enough,
+     * custom serializer can be provided.
+     */
+    stateSerialization?: { toJson?(state: S): any, fromJson?(data: any): S }
+}
+
+namespace PluginStateAnimation {
+    export type ApplyResult<S> = { kind: 'finished' } | { kind: 'next', state: S }
+    export interface Context<P extends PD.Params> {
+        params: PD.Values<P>,
+        plugin: PluginContext
+    }
+}
+