luvatrix 0.2.2__tar.gz → 0.2.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (192) hide show
  1. {luvatrix-0.2.2/luvatrix.egg-info → luvatrix-0.2.3}/PKG-INFO +1 -1
  2. {luvatrix-0.2.2 → luvatrix-0.2.3/luvatrix.egg-info}/PKG-INFO +1 -1
  3. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/__init__.py +1 -1
  4. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/core/app_runtime.py +9 -0
  5. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/core/interaction_work.py +19 -2
  6. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/core/unified_runtime.py +4 -0
  7. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/templates/native/android/app/src/main/java/com/luvatrix/app/MainActivity.kt +16 -4
  8. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/templates/native/android/app/src/main/python/luvatrix_android_boot.py +134 -10
  9. {luvatrix-0.2.2 → luvatrix-0.2.3}/pyproject.toml +1 -1
  10. {luvatrix-0.2.2 → luvatrix-0.2.3}/LICENSE +0 -0
  11. {luvatrix-0.2.2 → luvatrix-0.2.3}/MANIFEST.in +0 -0
  12. {luvatrix-0.2.2 → luvatrix-0.2.3}/README.md +0 -0
  13. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix/__init__.py +0 -0
  14. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix/app.py +0 -0
  15. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix/auth/__init__.py +0 -0
  16. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix/auth/calendar.py +0 -0
  17. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix/auth/google.py +0 -0
  18. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix/auth/sign_in.py +0 -0
  19. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix/auth/ui.py +0 -0
  20. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix.egg-info/SOURCES.txt +0 -0
  21. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix.egg-info/dependency_links.txt +0 -0
  22. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix.egg-info/entry_points.txt +0 -0
  23. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix.egg-info/requires.txt +0 -0
  24. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix.egg-info/top_level.txt +0 -0
  25. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/accel.py +0 -0
  26. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/core/__init__.py +0 -0
  27. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/core/audit.py +0 -0
  28. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/core/coordinates.py +0 -0
  29. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/core/debug_capture.py +0 -0
  30. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/core/debug_menu.py +0 -0
  31. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/core/display_runtime.py +0 -0
  32. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/core/energy_safety.py +0 -0
  33. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/core/engine.py +0 -0
  34. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/core/events.py +0 -0
  35. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/core/frame_rate_controller.py +0 -0
  36. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/core/hdi_thread.py +0 -0
  37. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/core/process_runtime.py +0 -0
  38. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/core/process_sdk.py +0 -0
  39. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/core/protocol_governance.py +0 -0
  40. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/core/scene_display_runtime.py +0 -0
  41. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/core/scene_graph.py +0 -0
  42. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/core/scene_rasterizer.py +0 -0
  43. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/core/sensor_manager.py +0 -0
  44. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/core/ui_frame_renderer.py +0 -0
  45. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/core/window_matrix.py +0 -0
  46. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/perf/copy_telemetry.py +0 -0
  47. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/platform/__init__.py +0 -0
  48. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/platform/android/__init__.py +0 -0
  49. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/platform/android/camera_processing_contract.py +0 -0
  50. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/platform/android/camera_style.py +0 -0
  51. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/platform/android/hdi_source.py +0 -0
  52. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/platform/android/runner.py +0 -0
  53. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/platform/android/scene_target.py +0 -0
  54. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/platform/android/sensors.py +0 -0
  55. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/platform/android/vulkan_target.py +0 -0
  56. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/platform/frame_pipeline.py +0 -0
  57. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/platform/ios/__init__.py +0 -0
  58. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/platform/ios/hdi_source.py +0 -0
  59. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/platform/ios/lifecycle.py +0 -0
  60. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/platform/ios/metal_backend.py +0 -0
  61. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/platform/ios/runner.py +0 -0
  62. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/platform/ios/scene_target.py +0 -0
  63. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/platform/ios/window_system.py +0 -0
  64. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/platform/macos/__init__.py +0 -0
  65. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/platform/macos/hdi_source.py +0 -0
  66. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/platform/macos/iohid_source.py +0 -0
  67. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/platform/macos/metal_backend.py +0 -0
  68. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/platform/macos/metal_presenter.py +0 -0
  69. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/platform/macos/metal_scene_target.py +0 -0
  70. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/platform/macos/sensors.py +0 -0
  71. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/platform/macos/vulkan_backend.py +0 -0
  72. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/platform/macos/vulkan_presenter.py +0 -0
  73. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/platform/macos/window_system.py +0 -0
  74. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/platform/package_sync.py +0 -0
  75. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/platform/vulkan_compat.py +0 -0
  76. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/platform/vulkan_scaling.py +0 -0
  77. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/platform/vulkan_setup.py +0 -0
  78. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/platform/web/__init__.py +0 -0
  79. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/platform/web/build.py +0 -0
  80. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/platform/web/command_buffer.py +0 -0
  81. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/platform/web/python_shim/luvatrix/__init__.py +0 -0
  82. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/platform/web/python_shim/luvatrix/app.py +0 -0
  83. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/platform/web/runtime_assets/index.html +0 -0
  84. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/platform/web/runtime_assets/runtime/command-buffer.js +0 -0
  85. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/platform/web/runtime_assets/runtime/input.js +0 -0
  86. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/platform/web/runtime_assets/runtime/luvatrix-web.js +0 -0
  87. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/platform/web/runtime_assets/runtime/package.json +0 -0
  88. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/platform/web/runtime_assets/runtime/renderers.js +0 -0
  89. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/platform/web/runtime_assets/runtime/spotify-bridge.js +0 -0
  90. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/platform/web/server.py +0 -0
  91. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/platform/web/websocket_target.py +0 -0
  92. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/render/__init__.py +0 -0
  93. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/render/framebuffer.py +0 -0
  94. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/render/svg.py +0 -0
  95. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/scaffold.py +0 -0
  96. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/targets/__init__.py +0 -0
  97. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/targets/base.py +0 -0
  98. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/targets/cpu_scene_target.py +0 -0
  99. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/targets/metal_target.py +0 -0
  100. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/targets/scene_target.py +0 -0
  101. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/targets/vulkan_target.py +0 -0
  102. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/targets/web_target.py +0 -0
  103. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/templates/native/android/.gitignore +0 -0
  104. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/templates/native/android/app/build.gradle.kts +0 -0
  105. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/templates/native/android/app/src/main/AndroidManifest.xml +0 -0
  106. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/templates/native/android/app/src/main/assets/luvatrix_bitmap_font.txt +0 -0
  107. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/templates/native/android/app/src/main/assets/luvatrix_launch_config.json +0 -0
  108. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/templates/native/android/app/src/main/assets/luvatrix_matrix_font_alpha.txt +0 -0
  109. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/templates/native/android/app/src/main/cpp/CMakeLists.txt +0 -0
  110. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/templates/native/android/app/src/main/cpp/luvatrix_camera_preview.frag +0 -0
  111. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/templates/native/android/app/src/main/cpp/luvatrix_camera_preview_shaders.h +0 -0
  112. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/templates/native/android/app/src/main/cpp/luvatrix_vulkan_renderer.cpp +0 -0
  113. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/templates/native/android/app/src/main/java/com/luvatrix/app/CameraBridge.kt +0 -0
  114. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/templates/native/android/app/src/main/java/com/luvatrix/app/LuvatrixVulkanView.kt +0 -0
  115. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/templates/native/android/app/src/main/java/com/luvatrix/app/NativeVulkan.kt +0 -0
  116. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/templates/native/android/app/src/main/python/.gitignore +0 -0
  117. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/templates/native/android/app/src/main/python/luvatrix_launch_config.json +0 -0
  118. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/templates/native/android/app/src/main/res/mipmap-hdpi/ic_launcher.png +0 -0
  119. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/templates/native/android/app/src/main/res/mipmap-mdpi/ic_launcher.png +0 -0
  120. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/templates/native/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png +0 -0
  121. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/templates/native/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png +0 -0
  122. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/templates/native/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png +0 -0
  123. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/templates/native/android/app/src/main/res/values/styles.xml +0 -0
  124. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/templates/native/android/build.gradle.kts +0 -0
  125. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/templates/native/android/gradle.properties +0 -0
  126. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/templates/native/android/gradlew +0 -0
  127. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/templates/native/android/scripts/emulator_acceptance.sh +0 -0
  128. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/templates/native/android/scripts/sync_python_assets.sh +0 -0
  129. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/templates/native/android/settings.gradle.kts +0 -0
  130. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/templates/native/ios/Luvatrix/AppDelegate.swift +0 -0
  131. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/templates/native/ios/Luvatrix/Assets.xcassets/AppIcon.appiconset/Contents.json +0 -0
  132. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/templates/native/ios/Luvatrix/Assets.xcassets/AppIcon.appiconset/icon.png +0 -0
  133. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/templates/native/ios/Luvatrix/Assets.xcassets/Contents.json +0 -0
  134. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/templates/native/ios/Luvatrix/Info.plist +0 -0
  135. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/templates/native/ios/Luvatrix/Luvatrix-Bridging-Header.h +0 -0
  136. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/templates/native/ios/Luvatrix/Luvatrix.entitlements +0 -0
  137. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/templates/native/ios/Luvatrix/PythonBridge.h +0 -0
  138. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/templates/native/ios/Luvatrix/PythonBridge.m +0 -0
  139. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/templates/native/ios/Luvatrix/main.swift +0 -0
  140. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/templates/native/ios/project.yml +0 -0
  141. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/templates/native/ios/scripts/setup_ios.sh +0 -0
  142. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/ui/__init__.py +0 -0
  143. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/ui/element.py +0 -0
  144. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_core/ui/page_loader.py +0 -0
  145. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_plot/__init__.py +0 -0
  146. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_plot/adapters/__init__.py +0 -0
  147. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_plot/adapters/normalize.py +0 -0
  148. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_plot/api.py +0 -0
  149. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_plot/compile/__init__.py +0 -0
  150. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_plot/compile/app_protocol.py +0 -0
  151. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_plot/display.py +0 -0
  152. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_plot/dynamic_axis.py +0 -0
  153. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_plot/errors.py +0 -0
  154. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_plot/figure.py +0 -0
  155. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_plot/live.py +0 -0
  156. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_plot/raster/__init__.py +0 -0
  157. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_plot/raster/canvas.py +0 -0
  158. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_plot/raster/draw_lines.py +0 -0
  159. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_plot/raster/draw_markers.py +0 -0
  160. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_plot/raster/draw_text.py +0 -0
  161. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_plot/raster/layers.py +0 -0
  162. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_plot/scales.py +0 -0
  163. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_plot/series.py +0 -0
  164. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_ui/__init__.py +0 -0
  165. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_ui/component_schema.py +0 -0
  166. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_ui/controls/__init__.py +0 -0
  167. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_ui/controls/button.py +0 -0
  168. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_ui/controls/interaction.py +0 -0
  169. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_ui/controls/stained_glass_button.py +0 -0
  170. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_ui/controls/svg_component.py +0 -0
  171. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_ui/controls/svg_renderer.py +0 -0
  172. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_ui/planes_protocol.py +0 -0
  173. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_ui/planes_runtime.py +0 -0
  174. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_ui/planes_v2_validator.py +0 -0
  175. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_ui/planning/__init__.py +0 -0
  176. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_ui/planning/agile_renderer.py +0 -0
  177. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_ui/planning/exporters.py +0 -0
  178. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_ui/planning/gantt_renderer.py +0 -0
  179. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_ui/planning/interaction.py +0 -0
  180. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_ui/planning/schema.py +0 -0
  181. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_ui/planning/validation.py +0 -0
  182. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_ui/style/__init__.py +0 -0
  183. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_ui/style/theme.py +0 -0
  184. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_ui/table/__init__.py +0 -0
  185. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_ui/table/component.py +0 -0
  186. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_ui/text/__init__.py +0 -0
  187. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_ui/text/component.py +0 -0
  188. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_ui/text/renderer.py +0 -0
  189. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_ui/text/wrapping.py +0 -0
  190. {luvatrix-0.2.2 → luvatrix-0.2.3}/luvatrix_ui/ui_ir.py +0 -0
  191. {luvatrix-0.2.2 → luvatrix-0.2.3}/main.py +0 -0
  192. {luvatrix-0.2.2 → luvatrix-0.2.3}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: luvatrix
3
- Version: 0.2.2
3
+ Version: 0.2.3
4
4
  Summary: Luvatrix runtime and plotting toolkit
5
5
  Author: Luvatrix contributors
6
6
  License-Expression: LicenseRef-Proprietary
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: luvatrix
3
- Version: 0.2.2
3
+ Version: 0.2.3
4
4
  Summary: Luvatrix runtime and plotting toolkit
5
5
  Author: Luvatrix contributors
6
6
  License-Expression: LicenseRef-Proprietary
@@ -1,4 +1,4 @@
1
1
  """Luvatrix runtime."""
2
2
 
3
3
  __all__ = ["__version__"]
4
- __version__ = "0.2.2"
4
+ __version__ = "0.2.3"
@@ -445,6 +445,13 @@ class AppContext:
445
445
  payload = self.runtime_telemetry_provider()
446
446
  return payload if isinstance(payload, dict) else {}
447
447
 
448
+ def has_presented_frame(self) -> bool:
449
+ """Return whether the runtime has successfully presented at least one frame."""
450
+ try:
451
+ return int(self.runtime_telemetry().get("frames_presented", 0)) > 0
452
+ except (TypeError, ValueError):
453
+ return False
454
+
448
455
  def begin_scene_frame(
449
456
  self,
450
457
  *,
@@ -1574,6 +1581,8 @@ def _parse_entrypoint(entrypoint: str) -> tuple[str, str]:
1574
1581
  def _load_module_from_app_dir(app_dir: Path, module_name: str):
1575
1582
  rel_parts = module_name.split(".")
1576
1583
  module_path = app_dir.joinpath(*rel_parts).with_suffix(".py")
1584
+ if not module_path.exists():
1585
+ module_path = module_path.with_suffix(".pyc")
1577
1586
  if not module_path.exists():
1578
1587
  raise ValueError(f"entrypoint module file not found: {module_name}")
1579
1588
  unique_name = f"luvatrix_app_{abs(hash((str(app_dir), module_name)))}"
@@ -20,7 +20,9 @@ class InteractionAwareWorkScheduler:
20
20
 
21
21
  Work and callbacks execute sequentially on one daemon thread. Running work
22
22
  is not preempted when interaction begins; the idle gate prevents queued
23
- work from starting until ``interaction_active`` returns false.
23
+ work from starting until ``interaction_active`` returns false. Pass
24
+ ``startup_ready=ctx.has_presented_frame`` to keep preparation from
25
+ competing with the app's first presentation.
24
26
 
25
27
  Pair with ``SwipeMomentumController`` using
26
28
  ``interaction_active=lambda: swipe.active`` and call
@@ -32,12 +34,14 @@ class InteractionAwareWorkScheduler:
32
34
  self,
33
35
  *,
34
36
  interaction_active: Callable[[], bool],
37
+ startup_ready: Callable[[], bool] | None = None,
35
38
  request_render: Callable[[], None] | None = None,
36
39
  on_error: Callable[[Hashable, Exception], None] | None = None,
37
40
  idle_poll_interval: float = 1.0 / 120.0,
38
41
  thread_name: str = "luvatrix-interaction-work",
39
42
  ) -> None:
40
43
  self.interaction_active = interaction_active
44
+ self.startup_ready = startup_ready
41
45
  self.request_render = request_render
42
46
  self.on_error = on_error
43
47
  self.idle_poll_interval = max(0.001, float(idle_poll_interval))
@@ -83,6 +87,11 @@ class InteractionAwareWorkScheduler:
83
87
  with self._condition:
84
88
  self._condition.notify_all()
85
89
 
90
+ def notify_startup_state_changed(self) -> None:
91
+ """Wake queued work after the startup gate becomes ready."""
92
+ with self._condition:
93
+ self._condition.notify_all()
94
+
86
95
  def wait_idle(self, timeout: float | None = None) -> bool:
87
96
  """Wait until queued/running work and its callbacks have completed."""
88
97
  deadline = None if timeout is None else time.monotonic() + max(0.0, float(timeout))
@@ -123,12 +132,20 @@ class InteractionAwareWorkScheduler:
123
132
  self._report_error(pending_key, exc)
124
133
  interaction_active = False
125
134
 
135
+ startup_ready = True
136
+ if self.startup_ready is not None:
137
+ try:
138
+ startup_ready = bool(self.startup_ready())
139
+ except Exception as exc:
140
+ self._report_error(pending_key, exc)
141
+ startup_ready = False
142
+
126
143
  with self._condition:
127
144
  if self._closed:
128
145
  return
129
146
  if not self._pending:
130
147
  continue
131
- if interaction_active:
148
+ if interaction_active or not startup_ready:
132
149
  self._condition.wait(self.idle_poll_interval)
133
150
  continue
134
151
  item = self._pending.popleft()
@@ -75,6 +75,7 @@ class UnifiedRuntime:
75
75
  self._active_provider = active_provider
76
76
  self._app_loop_rate = _RollingRate()
77
77
  self._app_loop_ticks = 0
78
+ self._frames_presented = 0
78
79
  self._scene_buffer = SceneGraphBuffer() if scene_target is not None and render_mode in ("auto", "scene") else None
79
80
  if render_mode == "scene" and scene_target is None:
80
81
  raise ValueError("render_mode='scene' requires a scene_target")
@@ -123,6 +124,7 @@ class UnifiedRuntime:
123
124
  "app_loop_fps": self._app_loop_rate.rate,
124
125
  "app_loop_ticks": int(self._app_loop_ticks),
125
126
  "app_active": int(self._is_active()),
127
+ "frames_presented": int(self._frames_presented),
126
128
  "scene_deduplicated_submissions": (
127
129
  int(self._scene_buffer.deduplicated_submissions) if self._scene_buffer is not None else 0
128
130
  ),
@@ -259,6 +261,7 @@ class UnifiedRuntime:
259
261
  matrix_tick = self._display_runtime.run_once(timeout=display_timeout)
260
262
  if matrix_tick is not None:
261
263
  frames_presented += 1
264
+ self._frames_presented = frames_presented
262
265
  sleep_for = rate.compute_sleep(
263
266
  loop_started_at=now,
264
267
  loop_finished_at=time.perf_counter(),
@@ -288,6 +291,7 @@ class UnifiedRuntime:
288
291
  active_target.stop()
289
292
  if self._scene_display_runtime is not None:
290
293
  frames_presented = self._scene_display_runtime.frames_presented
294
+ self._frames_presented = frames_presented
291
295
  return UnifiedRunResult(
292
296
  ticks_run=ticks_run,
293
297
  frames_presented=frames_presented,
@@ -11,6 +11,7 @@ import com.chaquo.python.android.AndroidPlatform
11
11
 
12
12
  class MainActivity : Activity() {
13
13
  private lateinit var luvatrixView: LuvatrixVulkanView
14
+ private lateinit var pythonModule: PyObject
14
15
 
15
16
  override fun onCreate(savedInstanceState: Bundle?) {
16
17
  super.onCreate(savedInstanceState)
@@ -24,17 +25,17 @@ class MainActivity : Activity() {
24
25
  Python.start(AndroidPlatform(this))
25
26
  }
26
27
  Log.i(TAG, "loading luvatrix_android_boot")
27
- val module = Python.getInstance().getModule("luvatrix_android_boot")
28
- pythonBridge = PythonBridge(module)
28
+ pythonModule = Python.getInstance().getModule("luvatrix_android_boot")
29
+ pythonBridge = PythonBridge(pythonModule)
29
30
 
30
31
  val importProbe = intent.getBooleanExtra("luvatrix_import_probe", false)
31
32
  Thread {
32
33
  try {
33
34
  Log.i(TAG, "starting Luvatrix visual runtime importProbe=$importProbe")
34
35
  if (importProbe) {
35
- module.callAttr("import_probe")
36
+ pythonModule.callAttr("import_probe")
36
37
  } else {
37
- module.callAttr("run_app_vulkan", luvatrixView)
38
+ pythonModule.callAttr("run_app_vulkan", luvatrixView)
38
39
  }
39
40
  Log.i(TAG, "Luvatrix visual runtime returned")
40
41
  } catch (exc: Throwable) {
@@ -44,6 +45,17 @@ class MainActivity : Activity() {
44
45
  }.start()
45
46
  }
46
47
 
48
+ override fun onDestroy() {
49
+ if (::pythonModule.isInitialized && ::luvatrixView.isInitialized) {
50
+ try {
51
+ pythonModule.callAttr("detach_android_view", luvatrixView)
52
+ } catch (exc: Throwable) {
53
+ Log.w(TAG, "could not detach destroyed Android view", exc)
54
+ }
55
+ }
56
+ super.onDestroy()
57
+ }
58
+
47
59
  override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
48
60
  super.onRequestPermissionsResult(requestCode, permissions, grantResults)
49
61
  if (requestCode == LuvatrixVulkanView.CAMERA_PERMISSION_REQUEST) {
@@ -8,6 +8,7 @@ import os
8
8
  from pathlib import Path
9
9
  import sys
10
10
  import tempfile
11
+ import threading
11
12
  import time
12
13
  import tomllib
13
14
  from urllib.parse import urlparse
@@ -20,6 +21,72 @@ if str(_ROOT) not in sys.path:
20
21
  _LAST_MARKER = ""
21
22
  _FRAME_COUNT = 0
22
23
  _ANDROID_VIEW = None
24
+ _RUNTIME_LOCK = threading.Lock()
25
+ _RUNTIME_RUNNING = False
26
+ _RUNTIME_VIEW_GENERATION = 0
27
+
28
+
29
+ class _AndroidViewPresenter:
30
+ """Rebinds a process-scoped runtime to the current Android Activity view."""
31
+
32
+ def __init__(self) -> None:
33
+ self._lock = threading.Lock()
34
+ self._view = None
35
+ self._last_presentation: tuple[str, tuple[object, ...]] | None = None
36
+
37
+ def bind(self, view) -> None:
38
+ with self._lock:
39
+ self._view = view
40
+ presentation = self._last_presentation
41
+ if presentation is not None:
42
+ self._present(view, *presentation)
43
+
44
+ def unbind(self, view) -> None:
45
+ with self._lock:
46
+ if self._view is view:
47
+ self._view = None
48
+
49
+ def current_view(self):
50
+ with self._lock:
51
+ return self._view
52
+
53
+ def presentRgba(self, rgba: bytes, revision: int, width: int, height: int) -> None:
54
+ self._remember_and_present("presentRgba", (rgba, revision, width, height))
55
+
56
+ def presentScene(
57
+ self,
58
+ scene_json: str,
59
+ revision: int,
60
+ logical_width: int,
61
+ logical_height: int,
62
+ presentation_mode: str = "",
63
+ ) -> None:
64
+ self._remember_and_present(
65
+ "presentScene",
66
+ (scene_json, revision, logical_width, logical_height, presentation_mode),
67
+ )
68
+
69
+ def __getattr__(self, name: str):
70
+ view = self.current_view()
71
+ if view is None:
72
+ raise AttributeError(name)
73
+ return getattr(view, name)
74
+
75
+ def _remember_and_present(self, method_name: str, args: tuple[object, ...]) -> None:
76
+ with self._lock:
77
+ self._last_presentation = (method_name, args)
78
+ view = self._view
79
+ if view is not None:
80
+ self._present(view, method_name, args)
81
+
82
+ @staticmethod
83
+ def _present(view, method_name: str, args: tuple[object, ...]) -> None:
84
+ method = getattr(view, method_name, None)
85
+ if callable(method):
86
+ method(*args)
87
+
88
+
89
+ _ANDROID_PRESENTER = _AndroidViewPresenter()
23
90
 
24
91
 
25
92
  def _log(message: str) -> None:
@@ -69,15 +136,40 @@ def run_headless_ticks(ticks: int = 5) -> str:
69
136
 
70
137
 
71
138
  def run_app_vulkan(view=None) -> str:
139
+ global _ANDROID_VIEW, _RUNTIME_RUNNING, _RUNTIME_VIEW_GENERATION
140
+ with _RUNTIME_LOCK:
141
+ if view is not None:
142
+ _ANDROID_VIEW = view
143
+ _ANDROID_PRESENTER.bind(view)
144
+ _RUNTIME_VIEW_GENERATION += 1
145
+ owner_generation = _RUNTIME_VIEW_GENERATION
146
+ if _RUNTIME_RUNNING:
147
+ return _mark("luvatrix visual reattached")
148
+ _RUNTIME_RUNNING = True
72
149
  try:
73
- configure_android_tls()
74
- import_probe()
75
- result = _run_visual_runtime(view)
76
- _log(f"luvatrix visual ticks={result.ticks_run} frames={result.frames_presented}")
77
- return _mark("luvatrix visual ok")
150
+ while True:
151
+ configure_android_tls()
152
+ import_probe()
153
+ result = _run_visual_runtime(_ANDROID_PRESENTER if view is not None else None)
154
+ _log(f"luvatrix visual ticks={result.ticks_run} frames={result.frames_presented}")
155
+ with _RUNTIME_LOCK:
156
+ if owner_generation == _RUNTIME_VIEW_GENERATION:
157
+ return _mark("luvatrix visual ok")
158
+ owner_generation = _RUNTIME_VIEW_GENERATION
159
+ _log("restarting visual runtime for replacement Android view")
78
160
  except Exception as exc:
79
161
  _log(f"luvatrix run_app_vulkan failed: {type(exc).__name__}: {exc}")
80
162
  raise
163
+ finally:
164
+ with _RUNTIME_LOCK:
165
+ _RUNTIME_RUNNING = False
166
+
167
+
168
+ def detach_android_view(view) -> None:
169
+ global _ANDROID_VIEW
170
+ _ANDROID_PRESENTER.unbind(view)
171
+ if _ANDROID_VIEW is view:
172
+ _ANDROID_VIEW = None
81
173
 
82
174
 
83
175
  def configure_android_tls() -> str:
@@ -320,8 +412,6 @@ def _run_visual_runtime(view):
320
412
  if view is not None and _truthy(config.get("low_latency_mode"), default=True):
321
413
  _apply_low_latency_mode(view, target_fps=target_fps, present_fps=present_fps)
322
414
  clear_android_input_events()
323
- if view is not None:
324
- _ANDROID_VIEW = view
325
415
  if view is not None and _should_start_camera_preview(config):
326
416
  _start_camera_preview(view)
327
417
 
@@ -526,10 +616,17 @@ def _paint_view(view, frames: int) -> None:
526
616
 
527
617
  def _app_dir() -> Path:
528
618
  config = _launch_config()
529
- configured = (_ROOT / str(config.get("app_dir", "luvatrix_app"))).resolve()
530
- if (configured / "app.toml").exists() and (configured / "app_main.py").exists():
619
+ configured_name = str(config.get("app_dir", "luvatrix_app"))
620
+ configured = (_ROOT / configured_name).resolve()
621
+ if (configured / "app.toml").exists() and any(
622
+ (configured / name).exists() for name in ("app_main.py", "app_main.pyc")
623
+ ):
531
624
  return configured
532
625
 
626
+ materialized_configured = _materialize_configured_app(configured_name)
627
+ if materialized_configured is not None:
628
+ return materialized_configured
629
+
533
630
  source = str(config.get("source_app_dir", "") or "")
534
631
  if source:
535
632
  packaged = (_ROOT / "examples" / Path(source).name).resolve()
@@ -562,7 +659,10 @@ def _app_dir() -> Path:
562
659
 
563
660
 
564
661
  def _import_configured_app_main() -> None:
565
- app_main = _app_dir() / "app_main.py"
662
+ app_dir = _app_dir()
663
+ app_main = app_dir / "app_main.py"
664
+ if not app_main.exists():
665
+ app_main = app_dir / "app_main.pyc"
566
666
  module_name = "luvatrix_configured_app_main"
567
667
  spec = importlib.util.spec_from_file_location(module_name, app_main)
568
668
  if spec is None or spec.loader is None:
@@ -576,6 +676,20 @@ def _import_configured_app_main() -> None:
576
676
  raise
577
677
 
578
678
 
679
+ def _materialize_configured_app(package_name: str) -> Path | None:
680
+ try:
681
+ from importlib import resources
682
+
683
+ package = importlib.import_module(package_name)
684
+ package_root = resources.files(package)
685
+ app_toml = package_root.joinpath("app.toml").read_text(encoding="utf-8")
686
+ app_main = package_root.joinpath("app_main.pyc").read_bytes()
687
+ except Exception:
688
+ return None
689
+
690
+ return _write_materialized_bytecode_app(package_name, app_toml, app_main)
691
+
692
+
579
693
  def _materialize_packaged_app(source_app_dir: str = "") -> Path | None:
580
694
  package_name = _configured_example_package(source_app_dir)
581
695
  try:
@@ -611,6 +725,16 @@ def _write_materialized_app(package_name: str, app_toml: str, app_main: str) ->
611
725
  dest.mkdir(parents=True, exist_ok=True)
612
726
  (dest / "app.toml").write_text(app_toml, encoding="utf-8")
613
727
  (dest / "app_main.py").write_text(app_main, encoding="utf-8")
728
+ (dest / "app_main.pyc").unlink(missing_ok=True)
729
+ return dest
730
+
731
+
732
+ def _write_materialized_bytecode_app(package_name: str, app_toml: str, app_main: bytes) -> Path:
733
+ dest = Path(tempfile.gettempdir()) / f"luvatrix_{package_name.replace('.', '_')}"
734
+ dest.mkdir(parents=True, exist_ok=True)
735
+ (dest / "app.toml").write_text(app_toml, encoding="utf-8")
736
+ (dest / "app_main.pyc").write_bytes(app_main)
737
+ (dest / "app_main.py").unlink(missing_ok=True)
614
738
  return dest
615
739
 
616
740
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "luvatrix"
7
- version = "0.2.2"
7
+ version = "0.2.3"
8
8
  description = "Luvatrix runtime and plotting toolkit"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.14,<3.15"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes