[Impeller Scene] Add SceneNodeValue for synchronously fetching loaded ipscenes (#38913)

diff --git a/lib/ui/experiments/scene.dart b/lib/ui/experiments/scene.dart
index abe610c..73e689b 100644
--- a/lib/ui/experiments/scene.dart
+++ b/lib/ui/experiments/scene.dart
@@ -17,14 +17,14 @@
   /// The asset must be a file produced as the output of the `scenec` importer.
   /// The constructed object should then be reused via the [shader]
   /// method to create [Shader] objects that can be used by [Shader.paint].
-  static Future<SceneNode> fromAsset(String assetKey) {
+  static SceneNodeValue fromAsset(String assetKey) {
     // The flutter tool converts all asset keys with spaces into URI
     // encoded paths (replacing ' ' with '%20', for example). We perform
     // the same encoding here so that users can load assets with the same
     // key they have written in the pubspec.
     final String encodedKey = Uri(path: Uri.encodeFull(assetKey)).path;
     {
-      final Future<SceneNode>? futureSceneNode = _ipsceneRegistry[encodedKey]?.target;
+      final SceneNodeValue? futureSceneNode = _ipsceneRegistry[encodedKey]?.target;
       if (futureSceneNode != null) {
         return futureSceneNode;
       }
@@ -45,14 +45,15 @@
       return null;
     }).then((_) => sceneNode);
 
-    _ipsceneRegistry[encodedKey] = WeakReference<Future<SceneNode>>(futureSceneNode);
-    return futureSceneNode;
+    final SceneNodeValue result = SceneNodeValue.fromFuture(futureSceneNode);
+    _ipsceneRegistry[encodedKey] = WeakReference<SceneNodeValue>(result);
+    return result;
   }
 
-  static SceneNode fromTransform(Float64List matrix4) {
+  static SceneNodeValue fromTransform(Float64List matrix4) {
     final SceneNode sceneNode = SceneNode._create();
     sceneNode._initFromTransform(matrix4);
-    return sceneNode;
+    return SceneNodeValue.fromValue(sceneNode);
   }
 
   void addChild(SceneNode sceneNode) {
@@ -75,11 +76,11 @@
   // SceneNode.fromAsset. It holds weak references to the SceneNodes so that the
   // case where an in-use ipscene is requested again can be fast, but scenes
   // that are no longer referenced are not retained because of the cache.
-  static final Map<String, WeakReference<Future<SceneNode>>> _ipsceneRegistry =
-      <String, WeakReference<Future<SceneNode>>>{};
+  static final Map<String, WeakReference<SceneNodeValue>> _ipsceneRegistry =
+      <String, WeakReference<SceneNodeValue>>{};
 
   static Future<void> _reinitializeScene(String assetKey) async {
-    final WeakReference<Future<SceneNode>>? sceneRef = _ipsceneRegistry == null
+    final WeakReference<SceneNodeValue>? sceneRef = _ipsceneRegistry == null
       ? null
       : _ipsceneRegistry[assetKey];
 
@@ -89,7 +90,7 @@
       return;
     }
 
-    final Future<SceneNode>? sceneNodeFuture = sceneRef.target;
+    final Future<SceneNode>? sceneNodeFuture = sceneRef.target?.future;
     if (sceneNodeFuture == null) {
       return;
     }
@@ -129,6 +130,52 @@
   SceneShader sceneShader() => SceneShader._(this, debugName: _debugName);
 }
 
+class SceneNodeValue {
+  SceneNodeValue._(this._future, this._value) {
+    _future?.then((SceneNode result) => _value = result);
+  }
+
+  static SceneNodeValue fromFuture(Future<SceneNode> future) {
+    return SceneNodeValue._(future, null);
+  }
+
+  static SceneNodeValue fromValue(SceneNode value) {
+    return SceneNodeValue._(null, value);
+  }
+
+  final Future<SceneNode>? _future;
+  SceneNode? _value;
+
+  bool get isComplete {
+    return _value != null;
+  }
+
+  Future<SceneNode>? get future {
+    return _future;
+  }
+
+  SceneNode? get value {
+    return _value;
+  }
+
+  /// Calls `callback` when the `SceneNode` has finished initializing. If the
+  /// initialization is already finished, `callback` is called synchronously.
+  SceneNodeValue whenComplete(void Function(SceneNode) callback) {
+    if (_value == null && _future == null) {
+      return this;
+    }
+
+    if (_value != null) {
+      callback(_value!);
+      return this;
+    }
+
+    // _future != null
+    _future!.then((SceneNode node) => callback(node));
+    return this;
+  }
+}
+
 /// A [Shader] generated from a [SceneNode].
 ///
 /// Instances of this class can be obtained from the