Introduce base rive_types.h
diff --git a/include/rive/refcnt.hpp b/include/rive/refcnt.hpp
index 8e45508..7edae60 100644
--- a/include/rive/refcnt.hpp
+++ b/include/rive/refcnt.hpp
@@ -5,7 +5,7 @@
 #ifndef _RIVE_REFCNT_HPP_
 #define _RIVE_REFCNT_HPP_
 
-#include <assert.h>
+#include "rive/rive_types.hpp"
 
 #include <atomic>
 #include <cstddef>
diff --git a/include/rive/rive_types.hpp b/include/rive/rive_types.hpp
new file mode 100644
index 0000000..4d39b6f
--- /dev/null
+++ b/include/rive/rive_types.hpp
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2022 Rive
+ */
+
+// This should always be included by any other rive files,
+// as it performs basic self-consistency checks, and provides
+// shared common types and macros.
+
+#ifndef _RIVE_TYPES_HPP_
+#define _RIVE_TYPES_HPP_
+
+// We treat NDEBUG is the root of truth from the user.
+// Our other symbols (DEBUG, RELEASE) must agree with it.
+// ... its ok if our client doesn't set these, we will do that...
+// ... they just can't set them inconsistently.
+
+#ifdef NDEBUG
+    // we're in release mode
+    #ifdef DEBUG
+        #error "can't define both DEBUG and NDEBUG"
+    #endif
+    #ifndef RELEASE
+        #define RELEASE
+    #endif
+#else
+    // we're in debug mode
+    #ifdef RELEASE
+        #error "can't define RELEASE and not NDEBUG"
+    #endif
+    #ifndef DEBUG
+        #define DEBUG
+    #endif
+#endif
+
+// We really like these headers, so we include them all the time.
+
+#include <assert.h>
+#include <cstddef>
+#include <cstdint>
+
+#endif  // rive_types