sonolus.py 0.1.5__tar.gz → 0.1.6__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.

Potentially problematic release.


This version of sonolus.py might be problematic. Click here for more details.

Files changed (168) hide show
  1. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/PKG-INFO +1 -1
  2. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/docs/concepts/cli.md +12 -0
  3. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/pyproject.toml +1 -1
  4. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/sonolus/build/cli.py +14 -3
  5. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/sonolus/build/project.py +30 -1
  6. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/sonolus/script/archetype.py +10 -1
  7. sonolus_py-0.1.6/sonolus/script/project.py +76 -0
  8. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/sonolus/script/sprite.py +1 -3
  9. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/uv.lock +1 -1
  10. sonolus_py-0.1.5/sonolus/script/project.py +0 -25
  11. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/.github/workflows/publish.yaml +0 -0
  12. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/.gitignore +0 -0
  13. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/.python-version +0 -0
  14. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/LICENSE +0 -0
  15. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/README.md +0 -0
  16. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/doc_stubs/__init__.py +0 -0
  17. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/doc_stubs/builtins.pyi +0 -0
  18. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/doc_stubs/math.pyi +0 -0
  19. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/doc_stubs/num.pyi +0 -0
  20. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/doc_stubs/random.pyi +0 -0
  21. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/docs/CNAME +0 -0
  22. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/docs/concepts/builtins.md +0 -0
  23. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/docs/concepts/constructs.md +0 -0
  24. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/docs/concepts/index.md +0 -0
  25. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/docs/concepts/project.md +0 -0
  26. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/docs/concepts/resources.md +0 -0
  27. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/docs/concepts/types.md +0 -0
  28. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/docs/index.md +0 -0
  29. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/docs/reference/builtins.md +0 -0
  30. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/docs/reference/index.md +0 -0
  31. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/docs/reference/math.md +0 -0
  32. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/docs/reference/random.md +0 -0
  33. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/docs/reference/sonolus.script.archetype.md +0 -0
  34. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/docs/reference/sonolus.script.array.md +0 -0
  35. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/docs/reference/sonolus.script.array_like.md +0 -0
  36. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/docs/reference/sonolus.script.bucket.md +0 -0
  37. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/docs/reference/sonolus.script.containers.md +0 -0
  38. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/docs/reference/sonolus.script.debug.md +0 -0
  39. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/docs/reference/sonolus.script.easing.md +0 -0
  40. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/docs/reference/sonolus.script.effect.md +0 -0
  41. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/docs/reference/sonolus.script.engine.md +0 -0
  42. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/docs/reference/sonolus.script.globals.md +0 -0
  43. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/docs/reference/sonolus.script.instruction.md +0 -0
  44. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/docs/reference/sonolus.script.interval.md +0 -0
  45. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/docs/reference/sonolus.script.iterator.md +0 -0
  46. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/docs/reference/sonolus.script.level.md +0 -0
  47. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/docs/reference/sonolus.script.num.md +0 -0
  48. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/docs/reference/sonolus.script.options.md +0 -0
  49. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/docs/reference/sonolus.script.particle.md +0 -0
  50. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/docs/reference/sonolus.script.print.md +0 -0
  51. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/docs/reference/sonolus.script.project.md +0 -0
  52. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/docs/reference/sonolus.script.quad.md +0 -0
  53. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/docs/reference/sonolus.script.record.md +0 -0
  54. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/docs/reference/sonolus.script.runtime.md +0 -0
  55. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/docs/reference/sonolus.script.sprite.md +0 -0
  56. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/docs/reference/sonolus.script.text.md +0 -0
  57. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/docs/reference/sonolus.script.timing.md +0 -0
  58. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/docs/reference/sonolus.script.transform.md +0 -0
  59. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/docs/reference/sonolus.script.ui.md +0 -0
  60. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/docs/reference/sonolus.script.values.md +0 -0
  61. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/docs/reference/sonolus.script.vec.md +0 -0
  62. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/mkdocs.yml +0 -0
  63. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/scripts/generate.py +0 -0
  64. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/scripts/runtimes/Engine/Tutorial/Blocks.json +0 -0
  65. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/scripts/runtimes/Functions.json +0 -0
  66. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/scripts/runtimes/Level/Play/Blocks.json +0 -0
  67. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/scripts/runtimes/Level/Preview/Blocks.json +0 -0
  68. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/scripts/runtimes/Level/Watch/Blocks.json +0 -0
  69. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/sonolus/__init__.py +0 -0
  70. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/sonolus/backend/__init__.py +0 -0
  71. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/sonolus/backend/blocks.py +0 -0
  72. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/sonolus/backend/excepthook.py +0 -0
  73. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/sonolus/backend/finalize.py +0 -0
  74. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/sonolus/backend/interpret.py +0 -0
  75. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/sonolus/backend/ir.py +0 -0
  76. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/sonolus/backend/mode.py +0 -0
  77. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/sonolus/backend/node.py +0 -0
  78. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/sonolus/backend/ops.py +0 -0
  79. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/sonolus/backend/optimize/__init__.py +0 -0
  80. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/sonolus/backend/optimize/allocate.py +0 -0
  81. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/sonolus/backend/optimize/constant_evaluation.py +0 -0
  82. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/sonolus/backend/optimize/copy_coalesce.py +0 -0
  83. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/sonolus/backend/optimize/dead_code.py +0 -0
  84. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/sonolus/backend/optimize/dominance.py +0 -0
  85. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/sonolus/backend/optimize/flow.py +0 -0
  86. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/sonolus/backend/optimize/inlining.py +0 -0
  87. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/sonolus/backend/optimize/liveness.py +0 -0
  88. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/sonolus/backend/optimize/optimize.py +0 -0
  89. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/sonolus/backend/optimize/passes.py +0 -0
  90. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/sonolus/backend/optimize/simplify.py +0 -0
  91. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/sonolus/backend/optimize/ssa.py +0 -0
  92. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/sonolus/backend/place.py +0 -0
  93. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/sonolus/backend/utils.py +0 -0
  94. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/sonolus/backend/visitor.py +0 -0
  95. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/sonolus/build/__init__.py +0 -0
  96. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/sonolus/build/collection.py +0 -0
  97. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/sonolus/build/compile.py +0 -0
  98. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/sonolus/build/engine.py +0 -0
  99. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/sonolus/build/level.py +0 -0
  100. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/sonolus/build/node.py +0 -0
  101. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/sonolus/py.typed +0 -0
  102. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/sonolus/script/__init__.py +0 -0
  103. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/sonolus/script/array.py +0 -0
  104. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/sonolus/script/array_like.py +0 -0
  105. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/sonolus/script/bucket.py +0 -0
  106. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/sonolus/script/containers.py +0 -0
  107. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/sonolus/script/debug.py +0 -0
  108. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/sonolus/script/easing.py +0 -0
  109. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/sonolus/script/effect.py +0 -0
  110. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/sonolus/script/engine.py +0 -0
  111. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/sonolus/script/globals.py +0 -0
  112. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/sonolus/script/instruction.py +0 -0
  113. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/sonolus/script/internal/__init__.py +0 -0
  114. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/sonolus/script/internal/builtin_impls.py +0 -0
  115. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/sonolus/script/internal/callbacks.py +0 -0
  116. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/sonolus/script/internal/constant.py +0 -0
  117. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/sonolus/script/internal/context.py +0 -0
  118. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/sonolus/script/internal/descriptor.py +0 -0
  119. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/sonolus/script/internal/dict_impl.py +0 -0
  120. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/sonolus/script/internal/error.py +0 -0
  121. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/sonolus/script/internal/generic.py +0 -0
  122. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/sonolus/script/internal/impl.py +0 -0
  123. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/sonolus/script/internal/introspection.py +0 -0
  124. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/sonolus/script/internal/math_impls.py +0 -0
  125. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/sonolus/script/internal/native.py +0 -0
  126. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/sonolus/script/internal/random.py +0 -0
  127. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/sonolus/script/internal/range.py +0 -0
  128. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/sonolus/script/internal/transient.py +0 -0
  129. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/sonolus/script/internal/tuple_impl.py +0 -0
  130. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/sonolus/script/internal/value.py +0 -0
  131. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/sonolus/script/interval.py +0 -0
  132. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/sonolus/script/iterator.py +0 -0
  133. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/sonolus/script/level.py +0 -0
  134. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/sonolus/script/num.py +0 -0
  135. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/sonolus/script/options.py +0 -0
  136. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/sonolus/script/particle.py +0 -0
  137. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/sonolus/script/pointer.py +0 -0
  138. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/sonolus/script/print.py +0 -0
  139. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/sonolus/script/quad.py +0 -0
  140. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/sonolus/script/record.py +0 -0
  141. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/sonolus/script/runtime.py +0 -0
  142. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/sonolus/script/text.py +0 -0
  143. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/sonolus/script/timing.py +0 -0
  144. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/sonolus/script/transform.py +0 -0
  145. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/sonolus/script/ui.py +0 -0
  146. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/sonolus/script/values.py +0 -0
  147. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/sonolus/script/vec.py +0 -0
  148. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/tests/__init__.py +0 -0
  149. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/tests/script/__init__.py +0 -0
  150. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/tests/script/conftest.py +0 -0
  151. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/tests/script/test_array.py +0 -0
  152. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/tests/script/test_array_map.py +0 -0
  153. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/tests/script/test_assert.py +0 -0
  154. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/tests/script/test_dict.py +0 -0
  155. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/tests/script/test_flow.py +0 -0
  156. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/tests/script/test_functions.py +0 -0
  157. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/tests/script/test_helpers.py +0 -0
  158. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/tests/script/test_interval.py +0 -0
  159. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/tests/script/test_match.py +0 -0
  160. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/tests/script/test_num.py +0 -0
  161. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/tests/script/test_operator.py +0 -0
  162. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/tests/script/test_random.py +0 -0
  163. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/tests/script/test_range.py +0 -0
  164. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/tests/script/test_record.py +0 -0
  165. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/tests/script/test_transform.py +0 -0
  166. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/tests/script/test_tuple.py +0 -0
  167. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/tests/script/test_var_array.py +0 -0
  168. {sonolus_py-0.1.5 → sonolus_py-0.1.6}/tests/script/test_vec.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: sonolus.py
3
- Version: 0.1.5
3
+ Version: 0.1.6
4
4
  Summary: Sonolus engine development in Python
5
5
  Requires-Python: >=3.13
6
6
  Description-Content-Type: text/markdown
@@ -14,3 +14,15 @@ To build the project, run the following command in the root directory of your pr
14
14
  ```bash
15
15
  sonolus-py build
16
16
  ```
17
+
18
+ ## Outputting the level schema
19
+ To output the level schema of the project, run the following command in the root directory of your project:
20
+
21
+ ```bash
22
+ sonolus-py schema
23
+ ```
24
+
25
+ ## Programmatic usage
26
+ The same functionality can be accessed programmatically as methods of a project.
27
+
28
+ See [Project][sonolus.script.project.Project] for more information.
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "sonolus.py"
3
- version = "0.1.5"
3
+ version = "0.1.6"
4
4
  description = "Sonolus engine development in Python"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.13"
@@ -2,6 +2,7 @@ import argparse
2
2
  import contextlib
3
3
  import http.server
4
4
  import importlib
5
+ import json
5
6
  import shutil
6
7
  import socket
7
8
  import socketserver
@@ -11,7 +12,7 @@ from time import perf_counter
11
12
 
12
13
  from sonolus.build.engine import package_engine
13
14
  from sonolus.build.level import package_level_data
14
- from sonolus.build.project import build_project_to_collection
15
+ from sonolus.build.project import build_project_to_collection, get_project_schema
15
16
  from sonolus.script.project import Project
16
17
 
17
18
 
@@ -147,6 +148,14 @@ def main():
147
148
  dev_parser.add_argument("--build-dir", type=str, default="./build")
148
149
  dev_parser.add_argument("--port", type=int, default=8000)
149
150
 
151
+ schema_parser = subparsers.add_parser("schema")
152
+ schema_parser.add_argument(
153
+ "module",
154
+ type=str,
155
+ nargs="?",
156
+ help="Module path (e.g., 'module.name'). If omitted, will auto-detect if only one module exists.",
157
+ )
158
+
150
159
  args = parser.parse_args()
151
160
 
152
161
  if not args.module:
@@ -161,16 +170,18 @@ def main():
161
170
  if project is None:
162
171
  sys.exit(1)
163
172
 
164
- build_dir = Path(args.build_dir)
165
-
166
173
  if args.command == "build":
174
+ build_dir = Path(args.build_dir)
167
175
  start_time = perf_counter()
168
176
  build_project(project, build_dir)
169
177
  end_time = perf_counter()
170
178
  print(f"Project built successfully to '{build_dir.resolve()}' in {end_time - start_time:.2f}s")
171
179
  elif args.command == "dev":
180
+ build_dir = Path(args.build_dir)
172
181
  start_time = perf_counter()
173
182
  build_collection(project, build_dir)
174
183
  end_time = perf_counter()
175
184
  print(f"Build finished in {end_time - start_time:.2f}s")
176
185
  run_server(build_dir / "site", port=args.port)
186
+ elif args.command == "schema":
187
+ print(json.dumps(get_project_schema(project), indent=2))
@@ -5,7 +5,7 @@ from sonolus.build.engine import package_engine
5
5
  from sonolus.build.level import package_level_data
6
6
  from sonolus.script.engine import Engine
7
7
  from sonolus.script.level import Level
8
- from sonolus.script.project import Project
8
+ from sonolus.script.project import Project, ProjectSchema
9
9
 
10
10
  BLANK_PNG = (
11
11
  b"\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x01\x00\x00\x00\x01\x01\x00\x00\x00\x007n\xf9$"
@@ -92,3 +92,32 @@ def load_resources_files_to_collection(base_path: Path) -> Collection:
92
92
  collection.load_from_scp(path)
93
93
  collection.load_from_source(base_path)
94
94
  return collection
95
+
96
+
97
+ def get_project_schema(project: Project) -> ProjectSchema:
98
+ by_archetype: dict[str, dict[str, bool]] = {}
99
+ for archetype in project.engine.data.play.archetypes:
100
+ fields = by_archetype.setdefault(archetype.name, {})
101
+ # If a field is exported, we should exclude it if it's imported in watch mode
102
+ for field in archetype._exported_keys_:
103
+ fields[field] = False
104
+ for field in archetype._imported_keys_:
105
+ fields[field] = True
106
+ for archetype in project.engine.data.watch.archetypes:
107
+ fields = by_archetype.setdefault(archetype.name, {})
108
+ for field in archetype._imported_keys_:
109
+ if field not in fields:
110
+ fields[field] = True
111
+ for archetype in project.engine.data.preview.archetypes:
112
+ fields = by_archetype.setdefault(archetype.name, {})
113
+ for field in archetype._imported_keys_:
114
+ fields[field] = True
115
+ return {
116
+ "archetypes": [
117
+ {
118
+ "name": name,
119
+ "fields": [*fields],
120
+ }
121
+ for name, fields in by_archetype.items()
122
+ ]
123
+ }
@@ -5,7 +5,7 @@ from collections.abc import Callable
5
5
  from dataclasses import dataclass
6
6
  from enum import Enum, StrEnum
7
7
  from types import FunctionType
8
- from typing import Annotated, Any, ClassVar, Self, get_origin
8
+ from typing import Annotated, Any, ClassVar, Self, TypedDict, get_origin
9
9
 
10
10
  from sonolus.backend.ir import IRConst, IRInstr
11
11
  from sonolus.backend.mode import Mode
@@ -307,6 +307,11 @@ class _ArchetypeLevelData:
307
307
  type _ArchetypeData = _ArchetypeSelfData | _ArchetypeReferenceData | _ArchetypeLevelData
308
308
 
309
309
 
310
+ class ArchetypeSchema(TypedDict):
311
+ name: str
312
+ fields: list[str]
313
+
314
+
310
315
  class _BaseArchetype:
311
316
  _is_comptime_value_ = True
312
317
 
@@ -401,6 +406,10 @@ class _BaseArchetype:
401
406
  data.extend(field.type._accept_(bound.arguments[field.name] or zeros(field.type))._to_list_())
402
407
  native_call(Op.Spawn, archetype_id, *(Num(x) for x in data))
403
408
 
409
+ @classmethod
410
+ def schema(cls) -> ArchetypeSchema:
411
+ return {"name": cls.name or "unnamed", "fields": list(cls._imported_fields_)}
412
+
404
413
  def _level_data_entries(self, level_refs: dict[Any, int] | None = None):
405
414
  if not isinstance(self._data_, _ArchetypeLevelData):
406
415
  raise RuntimeError("Entity is not level data")
@@ -0,0 +1,76 @@
1
+ from __future__ import annotations
2
+
3
+ from os import PathLike
4
+ from pathlib import Path
5
+ from typing import Self, TypedDict
6
+
7
+ from sonolus.script.archetype import ArchetypeSchema
8
+ from sonolus.script.engine import Engine
9
+ from sonolus.script.level import Level
10
+
11
+
12
+ class Project:
13
+ """A Sonolus.py project.
14
+
15
+ Args:
16
+ engine: The engine of the project.
17
+ levels: The levels of the project.
18
+ resources: The path to the resources of the project.
19
+ """
20
+
21
+ def __init__(
22
+ self,
23
+ engine: Engine,
24
+ levels: list[Level] | None = None,
25
+ resources: PathLike | None = None,
26
+ ):
27
+ self.engine = engine
28
+ self.levels = levels or []
29
+ self.resources = Path(resources or "resources")
30
+
31
+ def with_levels(self, levels: list[Level]) -> Self:
32
+ """Create a new project with the specified levels.
33
+
34
+ Args:
35
+ levels: The levels of the project.
36
+
37
+ Returns:
38
+ The new project.
39
+ """
40
+ return Project(self.engine, levels, self.resources)
41
+
42
+ def dev(self, build_dir: PathLike, port: int = 8080):
43
+ """Start a development server for the project.
44
+
45
+ Args:
46
+ build_dir: The path to the build directory.
47
+ port: The port of the development server.
48
+ """
49
+ from sonolus.build.cli import build_collection, run_server
50
+
51
+ build_collection(self, Path(build_dir))
52
+ run_server(Path(build_dir) / "site", port=port)
53
+
54
+ def build(self, build_dir: PathLike):
55
+ """Build the project.
56
+
57
+ Args:
58
+ build_dir: The path to the build directory.
59
+ """
60
+ from sonolus.build.cli import build_project
61
+
62
+ build_project(self, Path(build_dir))
63
+
64
+ def schema(self) -> ProjectSchema:
65
+ """Generate the schema of the project.
66
+
67
+ Returns:
68
+ The schema of the project.
69
+ """
70
+ from sonolus.build.project import get_project_schema
71
+
72
+ return get_project_schema(self)
73
+
74
+
75
+ class ProjectSchema(TypedDict):
76
+ archetypes: list[ArchetypeSchema]
@@ -353,9 +353,7 @@ class StandardSprite:
353
353
  SIMULTANEOUS_CONNECTION_PURPLE = Annotated[Sprite, sprite("#SIMULTANEOUS_CONNECTION_PURPLE")]
354
354
  SIMULTANEOUS_CONNECTION_CYAN = Annotated[Sprite, sprite("#SIMULTANEOUS_CONNECTION_CYAN")]
355
355
 
356
- SIMULTANEOUS_CONNECTION_NEUTRAL_SEAMLESS = Annotated[
357
- Sprite, sprite("#SIMULTANEOUS_CONNECTION_NEUTRAL_SEAMLESS")
358
- ]
356
+ SIMULTANEOUS_CONNECTION_NEUTRAL_SEAMLESS = Annotated[Sprite, sprite("#SIMULTANEOUS_CONNECTION_NEUTRAL_SEAMLESS")]
359
357
  SIMULTANEOUS_CONNECTION_RED_SEAMLESS = Annotated[Sprite, sprite("#SIMULTANEOUS_CONNECTION_RED_SEAMLESS")]
360
358
  SIMULTANEOUS_CONNECTION_GREEN_SEAMLESS = Annotated[Sprite, sprite("#SIMULTANEOUS_CONNECTION_GREEN_SEAMLESS")]
361
359
  SIMULTANEOUS_CONNECTION_BLUE_SEAMLESS = Annotated[Sprite, sprite("#SIMULTANEOUS_CONNECTION_BLUE_SEAMLESS")]
@@ -628,7 +628,7 @@ wheels = [
628
628
 
629
629
  [[package]]
630
630
  name = "sonolus-py"
631
- version = "0.1.5"
631
+ version = "0.1.6"
632
632
  source = { editable = "." }
633
633
 
634
634
  [package.dev-dependencies]
@@ -1,25 +0,0 @@
1
- from os import PathLike
2
- from pathlib import Path
3
-
4
- from sonolus.script.engine import Engine
5
- from sonolus.script.level import Level
6
-
7
-
8
- class Project:
9
- """A Sonolus.py project.
10
-
11
- Args:
12
- engine: The engine of the project.
13
- levels: The levels of the project.
14
- resources: The path to the resources of the project.
15
- """
16
-
17
- def __init__(
18
- self,
19
- engine: Engine,
20
- levels: list[Level] | None = None,
21
- resources: PathLike | None = None,
22
- ):
23
- self.engine = engine
24
- self.levels = levels or []
25
- self.resources = Path(resources or "resources")
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