sonolus.py 0.1.2__py3-none-any.whl → 0.1.4__py3-none-any.whl

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 (72) hide show
  1. sonolus/backend/allocate.py +125 -51
  2. sonolus/backend/blocks.py +756 -756
  3. sonolus/backend/coalesce.py +85 -0
  4. sonolus/backend/constant_evaluation.py +374 -0
  5. sonolus/backend/dead_code.py +80 -0
  6. sonolus/backend/dominance.py +111 -0
  7. sonolus/backend/excepthook.py +37 -37
  8. sonolus/backend/finalize.py +69 -69
  9. sonolus/backend/flow.py +121 -92
  10. sonolus/backend/inlining.py +150 -0
  11. sonolus/backend/ir.py +5 -3
  12. sonolus/backend/liveness.py +173 -0
  13. sonolus/backend/mode.py +24 -24
  14. sonolus/backend/node.py +40 -40
  15. sonolus/backend/ops.py +197 -197
  16. sonolus/backend/optimize.py +37 -9
  17. sonolus/backend/passes.py +52 -6
  18. sonolus/backend/simplify.py +47 -30
  19. sonolus/backend/ssa.py +187 -0
  20. sonolus/backend/utils.py +48 -48
  21. sonolus/backend/visitor.py +892 -880
  22. sonolus/build/cli.py +7 -1
  23. sonolus/build/compile.py +88 -90
  24. sonolus/build/engine.py +55 -5
  25. sonolus/build/level.py +24 -23
  26. sonolus/build/node.py +43 -43
  27. sonolus/script/archetype.py +23 -6
  28. sonolus/script/array.py +2 -2
  29. sonolus/script/bucket.py +191 -191
  30. sonolus/script/callbacks.py +127 -115
  31. sonolus/script/comptime.py +1 -1
  32. sonolus/script/containers.py +23 -0
  33. sonolus/script/debug.py +19 -3
  34. sonolus/script/easing.py +323 -0
  35. sonolus/script/effect.py +131 -131
  36. sonolus/script/engine.py +37 -1
  37. sonolus/script/globals.py +269 -269
  38. sonolus/script/graphics.py +200 -150
  39. sonolus/script/instruction.py +151 -0
  40. sonolus/script/internal/__init__.py +5 -5
  41. sonolus/script/internal/builtin_impls.py +144 -144
  42. sonolus/script/internal/context.py +12 -4
  43. sonolus/script/internal/descriptor.py +17 -17
  44. sonolus/script/internal/introspection.py +14 -14
  45. sonolus/script/internal/native.py +40 -38
  46. sonolus/script/internal/value.py +3 -3
  47. sonolus/script/interval.py +120 -112
  48. sonolus/script/iterator.py +214 -211
  49. sonolus/script/math.py +30 -1
  50. sonolus/script/num.py +1 -1
  51. sonolus/script/options.py +191 -191
  52. sonolus/script/particle.py +157 -157
  53. sonolus/script/pointer.py +30 -30
  54. sonolus/script/{preview.py → print.py} +81 -81
  55. sonolus/script/random.py +14 -0
  56. sonolus/script/range.py +58 -58
  57. sonolus/script/record.py +3 -3
  58. sonolus/script/runtime.py +45 -6
  59. sonolus/script/sprite.py +333 -333
  60. sonolus/script/text.py +407 -407
  61. sonolus/script/timing.py +42 -42
  62. sonolus/script/transform.py +77 -23
  63. sonolus/script/ui.py +160 -160
  64. sonolus/script/vec.py +81 -72
  65. {sonolus_py-0.1.2.dist-info → sonolus_py-0.1.4.dist-info}/METADATA +1 -2
  66. sonolus_py-0.1.4.dist-info/RECORD +84 -0
  67. {sonolus_py-0.1.2.dist-info → sonolus_py-0.1.4.dist-info}/WHEEL +1 -1
  68. {sonolus_py-0.1.2.dist-info → sonolus_py-0.1.4.dist-info}/licenses/LICENSE +21 -21
  69. sonolus/build/defaults.py +0 -32
  70. sonolus/script/icon.py +0 -73
  71. sonolus_py-0.1.2.dist-info/RECORD +0 -76
  72. {sonolus_py-0.1.2.dist-info → sonolus_py-0.1.4.dist-info}/entry_points.txt +0 -0
sonolus/script/timing.py CHANGED
@@ -1,42 +1,42 @@
1
- from sonolus.backend.ops import Op
2
- from sonolus.script.internal.native import native_function
3
-
4
-
5
- @native_function(Op.BeatToBPM)
6
- def beat_to_bpm(beat: float) -> float:
7
- raise NotImplementedError
8
-
9
-
10
- @native_function(Op.BeatToTime)
11
- def beat_to_time(beat: float) -> float:
12
- raise NotImplementedError
13
-
14
-
15
- @native_function(Op.BeatToStartingBeat)
16
- def beat_to_starting_beat(beat: float) -> float:
17
- raise NotImplementedError
18
-
19
-
20
- @native_function(Op.BeatToStartingTime)
21
- def beat_to_starting_time(beat: float) -> float:
22
- raise NotImplementedError
23
-
24
-
25
- @native_function(Op.TimeToScaledTime)
26
- def time_to_scaled_time(time: float) -> float:
27
- raise NotImplementedError
28
-
29
-
30
- @native_function(Op.TimeToStartingScaledTime)
31
- def time_to_starting_scaled_time(time: float) -> float:
32
- raise NotImplementedError
33
-
34
-
35
- @native_function(Op.TimeToStartingTime)
36
- def time_to_starting_time(time: float) -> float:
37
- raise NotImplementedError
38
-
39
-
40
- @native_function(Op.TimeToTimeScale)
41
- def time_to_timescale(time: float) -> float:
42
- raise NotImplementedError
1
+ from sonolus.backend.ops import Op
2
+ from sonolus.script.internal.native import native_function
3
+
4
+
5
+ @native_function(Op.BeatToBPM)
6
+ def beat_to_bpm(beat: float) -> float:
7
+ raise NotImplementedError
8
+
9
+
10
+ @native_function(Op.BeatToTime)
11
+ def beat_to_time(beat: float) -> float:
12
+ raise NotImplementedError
13
+
14
+
15
+ @native_function(Op.BeatToStartingBeat)
16
+ def beat_to_starting_beat(beat: float) -> float:
17
+ raise NotImplementedError
18
+
19
+
20
+ @native_function(Op.BeatToStartingTime)
21
+ def beat_to_starting_time(beat: float) -> float:
22
+ raise NotImplementedError
23
+
24
+
25
+ @native_function(Op.TimeToScaledTime)
26
+ def time_to_scaled_time(time: float) -> float:
27
+ raise NotImplementedError
28
+
29
+
30
+ @native_function(Op.TimeToStartingScaledTime)
31
+ def time_to_starting_scaled_time(time: float) -> float:
32
+ raise NotImplementedError
33
+
34
+
35
+ @native_function(Op.TimeToStartingTime)
36
+ def time_to_starting_time(time: float) -> float:
37
+ raise NotImplementedError
38
+
39
+
40
+ @native_function(Op.TimeToTimeScale)
41
+ def time_to_timescale(time: float) -> float:
42
+ raise NotImplementedError
@@ -16,93 +16,147 @@ class Transform2d(Record):
16
16
  a12: float
17
17
  a20: float
18
18
  a21: float
19
+ a22: float
19
20
 
20
21
  @classmethod
21
22
  def new(cls) -> Self:
23
+ """Create a new identity transform."""
22
24
  return cls(
23
25
  1, 0, 0,
24
26
  0, 1, 0,
25
- 0, 0,
27
+ 0, 0, 1,
26
28
  )
27
29
 
28
30
  def _compose(self,
29
31
  b00: float, b01: float, b02: float,
30
32
  b10: float, b11: float, b12: float,
31
- b20: float, b21: float,
33
+ b20: float, b21: float, b22: float,
32
34
  ) -> Self:
33
35
  """Multiply the matrix with another matrix on the left."""
34
36
  a00 = self.a00 * b00 + self.a10 * b01 + self.a20 * b02
35
37
  a01 = self.a01 * b00 + self.a11 * b01 + self.a21 * b02
36
- a02 = self.a02 * b00 + self.a12 * b01 + b02
38
+ a02 = self.a02 * b00 + self.a12 * b01 + self.a22 * b02
37
39
  a10 = self.a00 * b10 + self.a10 * b11 + self.a20 * b12
38
40
  a11 = self.a01 * b10 + self.a11 * b11 + self.a21 * b12
39
- a12 = self.a02 * b10 + self.a12 * b11 + b12
40
- a20 = self.a00 * b20 + self.a10 * b21 + b20
41
- a21 = self.a01 * b20 + self.a11 * b21 + b21
42
- a22 = self.a02 * b20 + self.a12 * b21 + 1
41
+ a12 = self.a02 * b10 + self.a12 * b11 + self.a22 * b12
42
+ a20 = self.a00 * b20 + self.a10 * b21 + self.a20 * b22
43
+ a21 = self.a01 * b20 + self.a11 * b21 + self.a21 * b22
44
+ a22 = self.a02 * b20 + self.a12 * b21 + self.a22 * b22
43
45
  return Transform2d(
44
- a00 / a22, a01 / a22, a02 / a22,
45
- a10 / a22, a11 / a22, a12 / a22,
46
- a20 / a22, a21 / a22,
46
+ a00, a01, a02,
47
+ a10, a11, a12,
48
+ a20, a21, a22,
47
49
  )
48
50
 
49
51
  def translate(self, translation: Vec2, /) -> Self:
52
+ """Translate along the x and y axes."""
50
53
  return self._compose(
51
54
  1, 0, translation.x,
52
55
  0, 1, translation.y,
53
- 0, 0,
56
+ 0, 0, 1,
54
57
  )
55
58
 
56
59
  def scale(self, factor: Vec2, /) -> Self:
60
+ """Scale around the origin."""
57
61
  return self._compose(
58
62
  factor.x, 0, 0,
59
63
  0, factor.y, 0,
60
- 0, 0,
64
+ 0, 0, 1,
61
65
  )
62
66
 
63
- def rotate(self, angle: float) -> Self:
67
+ def scale_about(self, factor: Vec2, /, pivot: Vec2) -> Self:
68
+ """Scale around the pivot."""
69
+ return self.translate(-pivot).scale(factor).translate(pivot)
70
+
71
+ def rotate(self, angle: float, /) -> Self:
72
+ """Rotate around the origin."""
64
73
  c = cos(angle)
65
74
  s = sin(angle)
66
75
  return self._compose(
67
76
  c, -s, 0,
68
77
  s, c, 0,
69
- 0, 0,
78
+ 0, 0, 1,
70
79
  )
71
80
 
72
- def shear_x(self, m: float) -> Self:
81
+ def rotate_about(self, angle: float, /, pivot: Vec2) -> Self:
82
+ """Rotate around the pivot."""
83
+ return self.translate(-pivot).rotate(angle).translate(pivot)
84
+
85
+ def shear_x(self, m: float, /) -> Self:
73
86
  """Shear along the x-axis."""
74
87
  return self._compose(
75
88
  1, m, 0,
76
89
  0, 1, 0,
77
- 0, 0,
90
+ 0, 0, 1,
78
91
  )
79
92
 
80
- def shear_y(self, m: float) -> Self:
93
+ def shear_y(self, m: float, /) -> Self:
81
94
  """Shear along the y-axis."""
82
95
  return self._compose(
83
96
  1, 0, 0,
84
97
  m, 1, 0,
85
- 0, 0,
98
+ 0, 0, 1,
86
99
  )
87
100
 
88
- def perspective_vanish_y(self, y: float) -> Self:
101
+ def perspective_vanish_y(self, y: float, /) -> Self:
102
+ """Apply perspective vanish along the y-axis with vanish point at the given y coordinate.
103
+
104
+ Note: Conveniently, the inverse can be obtained simply by negating the argument.
105
+ """
89
106
  return self._compose(
90
107
  1, 0, 0,
91
108
  0, 1, 0,
92
- 0, 1 / y,
109
+ 0, 1 / y, 1,
110
+ )
111
+
112
+ def perspective(self, foreground_y, vanishing_point: Vec2, /) -> Self:
113
+ """Apply a perspective transformation.
114
+
115
+ When the original y is 0, the transformed x coordinate will be unchanged and the y coordinates will
116
+ be equal to foreground_y.
117
+ As the original y coordinate approaches infinity in the direction of the vanishing point,
118
+ the transformed x and y coordinates will approach the vanishing point.
119
+ """
120
+ return (
121
+ self
122
+ .perspective_vanish_y(vanishing_point.y - foreground_y)
123
+ .shear_x(vanishing_point.x / (vanishing_point.y - foreground_y))
124
+ .translate(Vec2(0, foreground_y))
93
125
  )
94
126
 
95
- def compose(self, other: Self) -> Self:
127
+ def inverse_perspective(self, foreground_y, vanishing_point: Vec2, /) -> Self:
128
+ """Apply the inverse of a perspective transformation."""
129
+ return (
130
+ self
131
+ .translate(Vec2(0, -foreground_y))
132
+ .shear_x(-vanishing_point.x / (vanishing_point.y - foreground_y))
133
+ .perspective_vanish_y(-vanishing_point.y + foreground_y)
134
+ )
135
+
136
+ def normalize(self):
137
+ """Normalize the transform to have a 1 in the bottom right corner."""
138
+ return Transform2d(
139
+ self.a00 / self.a22, self.a01 / self.a22, self.a02 / self.a22,
140
+ self.a10 / self.a22, self.a11 / self.a22, self.a12 / self.a22,
141
+ self.a20 / self.a22, self.a21 / self.a22, 1,
142
+ )
143
+
144
+ def compose(self, other: Self, /) -> Self:
145
+ """Compose with another transform which is applied after this transform."""
96
146
  return self._compose(
97
147
  other.a00, other.a01, other.a02,
98
148
  other.a10, other.a11, other.a12,
99
- other.a20, other.a21,
149
+ other.a20, other.a21, other.a22,
100
150
  )
101
151
 
152
+ def compose_before(self, other: Self, /) -> Self:
153
+ """Compose with another transform which is applied before this transform."""
154
+ return other.compose(self)
155
+
102
156
  def transform_vec(self, v: Vec2) -> Vec2:
103
157
  x = self.a00 * v.x + self.a01 * v.y + self.a02
104
158
  y = self.a10 * v.x + self.a11 * v.y + self.a12
105
- w = self.a20 * v.x + self.a21 * v.y + 1
159
+ w = self.a20 * v.x + self.a21 * v.y + self.a22
106
160
  return Vec2(x / w, y / w)
107
161
 
108
162
  def transform_quad(self, quad: QuadLike) -> Quad:
sonolus/script/ui.py CHANGED
@@ -1,160 +1,160 @@
1
- from dataclasses import dataclass, field
2
- from typing import Literal
3
-
4
- UiMetric = Literal[
5
- "arcade",
6
- "arcadePercentage",
7
- "accuracy",
8
- "accuracyPercentage",
9
- "life",
10
- "perfect",
11
- "perfectPercentage",
12
- "greatGoodMiss",
13
- "greatGoodMissPercentage",
14
- "miss",
15
- "missPercentage",
16
- "errorHeatmap",
17
- ]
18
-
19
- UiJudgmentErrorStyle = Literal[
20
- "none",
21
- "plus",
22
- "minus",
23
- "arrowUp",
24
- "arrowDown",
25
- "arrowLeft",
26
- "arrowRight",
27
- "triangleUp",
28
- "triangleDown",
29
- "triangleLeft",
30
- "triangleRight",
31
- ]
32
-
33
- UiJudgmentErrorPlacement = Literal["both", "left", "right"]
34
-
35
- EaseType = Literal[
36
- "linear",
37
- "none",
38
- "inSine",
39
- "inQuad",
40
- "inCubic",
41
- "inQuart",
42
- "inQuint",
43
- "inExpo",
44
- "inCirc",
45
- "inBack",
46
- "inElastic",
47
- "outSine",
48
- "outQuad",
49
- "outCubic",
50
- "outQuart",
51
- "outQuint",
52
- "outExpo",
53
- "outCirc",
54
- "outBack",
55
- "outElastic",
56
- "inOutSine",
57
- "inOutQuad",
58
- "inOutCubic",
59
- "inOutQuart",
60
- "inOutQuint",
61
- "inOutExpo",
62
- "inOutCirc",
63
- "inOutBack",
64
- "inOutElastic",
65
- "outInSine",
66
- "outInQuad",
67
- "outInCubic",
68
- "outInQuart",
69
- "outInQuint",
70
- "outInExpo",
71
- "outInCirc",
72
- "outInBack",
73
- "outInElastic",
74
- ]
75
-
76
-
77
- @dataclass
78
- class UiAnimationTween:
79
- start: float
80
- end: float
81
- duration: float
82
- ease: EaseType
83
-
84
- def to_dict(self):
85
- return {
86
- "from": self.start,
87
- "to": self.end,
88
- "duration": self.duration,
89
- "ease": self.ease,
90
- }
91
-
92
-
93
- @dataclass
94
- class UiAnimation:
95
- scale: UiAnimationTween = field(default_factory=lambda: UiAnimationTween(1, 1, 0, "none"))
96
- alpha: UiAnimationTween = field(default_factory=lambda: UiAnimationTween(1, 0, 0.2, "outCubic"))
97
-
98
- def to_dict(self):
99
- return {
100
- "scale": self.scale.to_dict(),
101
- "alpha": self.alpha.to_dict(),
102
- }
103
-
104
-
105
- @dataclass
106
- class UiVisibility:
107
- scale: float = 1.0
108
- alpha: float = 1.0
109
-
110
- def to_dict(self):
111
- return {
112
- "scale": self.scale,
113
- "alpha": self.alpha,
114
- }
115
-
116
-
117
- @dataclass
118
- class UiConfig:
119
- scope: str | None = None
120
- primary_metric: UiMetric = "arcade"
121
- secondary_metric: UiMetric = "life"
122
- menu_visibility: UiVisibility = field(default_factory=UiVisibility)
123
- judgment_visibility: UiVisibility = field(default_factory=UiVisibility)
124
- combo_visibility: UiVisibility = field(default_factory=UiVisibility)
125
- primary_metric_visibility: UiVisibility = field(default_factory=UiVisibility)
126
- secondary_metric_visibility: UiVisibility = field(default_factory=UiVisibility)
127
- progress_visibility: UiVisibility = field(default_factory=UiVisibility)
128
- tutorial_navigation_visibility: UiVisibility = field(default_factory=UiVisibility)
129
- tutorial_instruction_visibility: UiVisibility = field(default_factory=UiVisibility)
130
- judgment_animation: UiAnimation = field(default_factory=UiAnimation)
131
- combo_animation: UiAnimation = field(
132
- default_factory=lambda: UiAnimation(
133
- scale=UiAnimationTween(1.2, 1, 0.2, "inCubic"), alpha=UiAnimationTween(1, 1, 0, "none")
134
- )
135
- )
136
- judgment_error_style: UiJudgmentErrorStyle = "none"
137
- judgment_error_placement: UiJudgmentErrorPlacement = "both"
138
- judgment_error_min: float = 0.0
139
-
140
- def to_dict(self):
141
- data = {
142
- "primaryMetric": self.primary_metric,
143
- "secondaryMetric": self.secondary_metric,
144
- "menuVisibility": self.menu_visibility.to_dict(),
145
- "judgmentVisibility": self.judgment_visibility.to_dict(),
146
- "comboVisibility": self.combo_visibility.to_dict(),
147
- "primaryMetricVisibility": self.primary_metric_visibility.to_dict(),
148
- "secondaryMetricVisibility": self.secondary_metric_visibility.to_dict(),
149
- "progressVisibility": self.progress_visibility.to_dict(),
150
- "tutorialNavigationVisibility": self.tutorial_navigation_visibility.to_dict(),
151
- "tutorialInstructionVisibility": self.tutorial_instruction_visibility.to_dict(),
152
- "judgmentAnimation": self.judgment_animation.to_dict(),
153
- "comboAnimation": self.combo_animation.to_dict(),
154
- "judgmentErrorStyle": self.judgment_error_style,
155
- "judgmentErrorPlacement": self.judgment_error_placement,
156
- "judgmentErrorMin": self.judgment_error_min,
157
- }
158
- if self.scope is not None:
159
- data["scope"] = self.scope
160
- return data
1
+ from dataclasses import dataclass, field
2
+ from typing import Literal
3
+
4
+ UiMetric = Literal[
5
+ "arcade",
6
+ "arcadePercentage",
7
+ "accuracy",
8
+ "accuracyPercentage",
9
+ "life",
10
+ "perfect",
11
+ "perfectPercentage",
12
+ "greatGoodMiss",
13
+ "greatGoodMissPercentage",
14
+ "miss",
15
+ "missPercentage",
16
+ "errorHeatmap",
17
+ ]
18
+
19
+ UiJudgmentErrorStyle = Literal[
20
+ "none",
21
+ "plus",
22
+ "minus",
23
+ "arrowUp",
24
+ "arrowDown",
25
+ "arrowLeft",
26
+ "arrowRight",
27
+ "triangleUp",
28
+ "triangleDown",
29
+ "triangleLeft",
30
+ "triangleRight",
31
+ ]
32
+
33
+ UiJudgmentErrorPlacement = Literal["both", "left", "right"]
34
+
35
+ EaseType = Literal[
36
+ "linear",
37
+ "none",
38
+ "inSine",
39
+ "inQuad",
40
+ "inCubic",
41
+ "inQuart",
42
+ "inQuint",
43
+ "inExpo",
44
+ "inCirc",
45
+ "inBack",
46
+ "inElastic",
47
+ "outSine",
48
+ "outQuad",
49
+ "outCubic",
50
+ "outQuart",
51
+ "outQuint",
52
+ "outExpo",
53
+ "outCirc",
54
+ "outBack",
55
+ "outElastic",
56
+ "inOutSine",
57
+ "inOutQuad",
58
+ "inOutCubic",
59
+ "inOutQuart",
60
+ "inOutQuint",
61
+ "inOutExpo",
62
+ "inOutCirc",
63
+ "inOutBack",
64
+ "inOutElastic",
65
+ "outInSine",
66
+ "outInQuad",
67
+ "outInCubic",
68
+ "outInQuart",
69
+ "outInQuint",
70
+ "outInExpo",
71
+ "outInCirc",
72
+ "outInBack",
73
+ "outInElastic",
74
+ ]
75
+
76
+
77
+ @dataclass
78
+ class UiAnimationTween:
79
+ start: float
80
+ end: float
81
+ duration: float
82
+ ease: EaseType
83
+
84
+ def to_dict(self):
85
+ return {
86
+ "from": self.start,
87
+ "to": self.end,
88
+ "duration": self.duration,
89
+ "ease": self.ease,
90
+ }
91
+
92
+
93
+ @dataclass
94
+ class UiAnimation:
95
+ scale: UiAnimationTween = field(default_factory=lambda: UiAnimationTween(1, 1, 0, "none"))
96
+ alpha: UiAnimationTween = field(default_factory=lambda: UiAnimationTween(1, 0, 0.2, "outCubic"))
97
+
98
+ def to_dict(self):
99
+ return {
100
+ "scale": self.scale.to_dict(),
101
+ "alpha": self.alpha.to_dict(),
102
+ }
103
+
104
+
105
+ @dataclass
106
+ class UiVisibility:
107
+ scale: float = 1.0
108
+ alpha: float = 1.0
109
+
110
+ def to_dict(self):
111
+ return {
112
+ "scale": self.scale,
113
+ "alpha": self.alpha,
114
+ }
115
+
116
+
117
+ @dataclass
118
+ class UiConfig:
119
+ scope: str | None = None
120
+ primary_metric: UiMetric = "arcade"
121
+ secondary_metric: UiMetric = "life"
122
+ menu_visibility: UiVisibility = field(default_factory=UiVisibility)
123
+ judgment_visibility: UiVisibility = field(default_factory=UiVisibility)
124
+ combo_visibility: UiVisibility = field(default_factory=UiVisibility)
125
+ primary_metric_visibility: UiVisibility = field(default_factory=UiVisibility)
126
+ secondary_metric_visibility: UiVisibility = field(default_factory=UiVisibility)
127
+ progress_visibility: UiVisibility = field(default_factory=UiVisibility)
128
+ tutorial_navigation_visibility: UiVisibility = field(default_factory=UiVisibility)
129
+ tutorial_instruction_visibility: UiVisibility = field(default_factory=UiVisibility)
130
+ judgment_animation: UiAnimation = field(default_factory=UiAnimation)
131
+ combo_animation: UiAnimation = field(
132
+ default_factory=lambda: UiAnimation(
133
+ scale=UiAnimationTween(1.2, 1, 0.2, "inCubic"), alpha=UiAnimationTween(1, 1, 0, "none")
134
+ )
135
+ )
136
+ judgment_error_style: UiJudgmentErrorStyle = "none"
137
+ judgment_error_placement: UiJudgmentErrorPlacement = "both"
138
+ judgment_error_min: float = 0.0
139
+
140
+ def to_dict(self):
141
+ data = {
142
+ "primaryMetric": self.primary_metric,
143
+ "secondaryMetric": self.secondary_metric,
144
+ "menuVisibility": self.menu_visibility.to_dict(),
145
+ "judgmentVisibility": self.judgment_visibility.to_dict(),
146
+ "comboVisibility": self.combo_visibility.to_dict(),
147
+ "primaryMetricVisibility": self.primary_metric_visibility.to_dict(),
148
+ "secondaryMetricVisibility": self.secondary_metric_visibility.to_dict(),
149
+ "progressVisibility": self.progress_visibility.to_dict(),
150
+ "tutorialNavigationVisibility": self.tutorial_navigation_visibility.to_dict(),
151
+ "tutorialInstructionVisibility": self.tutorial_instruction_visibility.to_dict(),
152
+ "judgmentAnimation": self.judgment_animation.to_dict(),
153
+ "comboAnimation": self.combo_animation.to_dict(),
154
+ "judgmentErrorStyle": self.judgment_error_style,
155
+ "judgmentErrorPlacement": self.judgment_error_placement,
156
+ "judgmentErrorMin": self.judgment_error_min,
157
+ }
158
+ if self.scope is not None:
159
+ data["scope"] = self.scope
160
+ return data