take animation for isTranslucent
diff --git a/include/rive/animation/linear_animation.hpp b/include/rive/animation/linear_animation.hpp
index 717351f..68e52c1 100644
--- a/include/rive/animation/linear_animation.hpp
+++ b/include/rive/animation/linear_animation.hpp
@@ -13,6 +13,7 @@
     private:
         std::vector<KeyedObject*> m_KeyedObjects;
 
+        friend class Artboard;
     public:
         ~LinearAnimation();
         StatusCode onAddedDirty(CoreContext* context) override;
@@ -36,4 +37,4 @@
     };
 } // namespace rive
 
-#endif
\ No newline at end of file
+#endif
diff --git a/include/rive/artboard.hpp b/include/rive/artboard.hpp
index a418d15..c3afe0c 100644
--- a/include/rive/artboard.hpp
+++ b/include/rive/artboard.hpp
@@ -74,7 +74,7 @@
         const std::vector<Core*>& objects() const { return m_Objects; }
 
         AABB bounds() const;
-        bool isTranslucent() const;
+        bool isTranslucent(const LinearAnimation*) const;
 
         template <typename T = Component> T* find(std::string name)
         {
diff --git a/include/rive/shapes/paint/linear_gradient.hpp b/include/rive/shapes/paint/linear_gradient.hpp
index 4ac2ad3..a4a17a4 100644
--- a/include/rive/shapes/paint/linear_gradient.hpp
+++ b/include/rive/shapes/paint/linear_gradient.hpp
@@ -31,7 +31,8 @@
         void opacityChanged() override;
         void renderOpacityChanged() override;
         virtual void makeGradient(const Vec2D& start, const Vec2D& end);
+        bool onIsTranslucent() const override;
     };
 } // namespace rive
 
-#endif
\ No newline at end of file
+#endif
diff --git a/include/rive/shapes/paint/shape_paint.hpp b/include/rive/shapes/paint/shape_paint.hpp
index c450134..ad61ea2 100644
--- a/include/rive/shapes/paint/shape_paint.hpp
+++ b/include/rive/shapes/paint/shape_paint.hpp
@@ -40,7 +40,11 @@
         /// ShapePaint. It'll be one of SolidColor, LinearGradient, or
         /// RadialGradient.
         Component* paint() const { return m_PaintMutator->component(); }
+        
+        bool isTranslucent() const {
+            return m_PaintMutator->isTranslucent();
+        }
     };
 } // namespace rive
 
-#endif
\ No newline at end of file
+#endif
diff --git a/include/rive/shapes/paint/shape_paint_mutator.hpp b/include/rive/shapes/paint/shape_paint_mutator.hpp
index b046900..6e69c58 100644
--- a/include/rive/shapes/paint/shape_paint_mutator.hpp
+++ b/include/rive/shapes/paint/shape_paint_mutator.hpp
@@ -21,11 +21,17 @@
 
         RenderPaint* renderPaint() const { return m_RenderPaint; }
 
+        virtual bool onIsTranslucent() const = 0;
+
     public:
         float renderOpacity() const { return m_RenderOpacity; }
         void renderOpacity(float value);
 
         Component* component() const { return m_Component; }
+        
+        bool isTranslucent() const {
+            return m_RenderOpacity < 1 || this->onIsTranslucent();
+        }
     };
 } // namespace rive
-#endif
\ No newline at end of file
+#endif
diff --git a/include/rive/shapes/paint/solid_color.hpp b/include/rive/shapes/paint/solid_color.hpp
index 26b822f..a662e9d 100644
--- a/include/rive/shapes/paint/solid_color.hpp
+++ b/include/rive/shapes/paint/solid_color.hpp
@@ -12,7 +12,8 @@
     protected:
         void renderOpacityChanged() override;
         void colorValueChanged() override;
+        bool onIsTranslucent() const override;
     };
 } // namespace rive
 
-#endif
\ No newline at end of file
+#endif
diff --git a/src/artboard.cpp b/src/artboard.cpp
index 3d27e37..1b59a85 100644
--- a/src/artboard.cpp
+++ b/src/artboard.cpp
@@ -6,6 +6,7 @@
 #include "rive/draw_target.hpp"
 #include "rive/draw_target_placement.hpp"
 #include "rive/drawable.hpp"
+#include "rive/animation/keyed_object.hpp"
 #include "rive/node.hpp"
 #include "rive/renderer.hpp"
 #include "rive/shapes/paint/shape_paint.hpp"
@@ -486,11 +487,23 @@
 
 AABB Artboard::bounds() const { return AABB(0.0f, 0.0f, width(), height()); }
 
-bool Artboard::isTranslucent() const {
-    constexpr float effectlyOpaqueAlpha = 0.999f;   // will turn into 0xFF when drawn
+bool Artboard::isTranslucent(const LinearAnimation* anim) const {
+    // For now we're conservative/lazy -- if we see that any of our paints are animated
+    // we assume that might make it non-opaque, so we early out
+    for (const auto obj : anim->m_KeyedObjects) {
+        auto ptr = this->resolve(obj->objectId());
+        for (const auto sp : m_ShapePaints) {
+            if (ptr == sp) {
+                return true;
+            }
+        }
+    }
+
+    // If we get here, we have no animations, so just check our paints for opacity
+
     for (const auto sp : m_ShapePaints) {
-        if (sp->renderOpacity() >= effectlyOpaqueAlpha) {
-            return false;   // one opaque background fill is all we need to be opaque
+        if (!sp->isTranslucent()) {
+            return false;   // one opaque fill is sufficient to be opaque
         }
     }
     return true;
diff --git a/src/shapes/paint/linear_gradient.cpp b/src/shapes/paint/linear_gradient.cpp
index 05e1587..8f680de 100644
--- a/src/shapes/paint/linear_gradient.cpp
+++ b/src/shapes/paint/linear_gradient.cpp
@@ -125,4 +125,14 @@
 void LinearGradient::startYChanged() { addDirt(ComponentDirt::Transform); }
 void LinearGradient::endXChanged() { addDirt(ComponentDirt::Transform); }
 void LinearGradient::endYChanged() { addDirt(ComponentDirt::Transform); }
-void LinearGradient::opacityChanged() { markGradientDirty(); }
\ No newline at end of file
+void LinearGradient::opacityChanged() { markGradientDirty(); }
+
+bool LinearGradient::onIsTranslucent() const {
+    for (const auto stop : m_Stops) {
+        unsigned alpha = stop->colorValue() >> 24;  // helper for this?
+        if (alpha != 0xFF) {
+            return true;
+        }
+    }
+    return false;   // all of our stops are opaque
+}
diff --git a/src/shapes/paint/solid_color.cpp b/src/shapes/paint/solid_color.cpp
index 47f4ea7..66a4c06 100644
--- a/src/shapes/paint/solid_color.cpp
+++ b/src/shapes/paint/solid_color.cpp
@@ -30,4 +30,9 @@
         colorModulateOpacity((unsigned int)colorValue(), renderOpacity()));
 }
 
-void SolidColor::colorValueChanged() { renderOpacityChanged(); }
\ No newline at end of file
+void SolidColor::colorValueChanged() { renderOpacityChanged(); }
+
+bool SolidColor::onIsTranslucent() const {
+    unsigned alpha = colorValue() >> 24;
+    return alpha != 0xFF;
+}