Welcome!
This is the community forum for my apps Pythonista and Editorial.
For individual support questions, you can also send an email. If you have a very short question or just want to say hello — I'm @olemoritz on Twitter.
Scripter - Pythonista UI animation framework built on ui.View.update()
-
And courtesy of iOS 11 screen recording, here’s a video of the demo.
-
Hmm...I must be doing something wrong. Tried to run scripter.py ( to see demo) but all I get is https://imgur.com/a/na0Nx
-
@ihf, I did not test on iPad, and
present
had a wrong argument.Either download the latest or change line 539 to:
v.present('full_screen')
-
@mikael Thanks that worked! (In the version I have, it was line 552).
-
@omz, is there a way to access the various timing options in
scene
Action
as a function of t? Would like to have the option of using those in Scripter. -
See https://github.com/controversial/ui2/blob/master/ui2/animate.py
The above is mainly for ui animation. You may look at scene_drawing.py code to see how various timing options are implemented.
-
@enceladus, thanks, your answer guided me on a hunt through UIKit and SceneKit docs. I could not find the easing functions conveniently exposed by Apple.
-
scene_drawing.py in modules/standard library 3.5/site-packages. You can use curve_sinodial, curve_ease_in like functions.
-
current_func = lambda s,t,d:s+curve_sinodial(t)*d should work (I am outside and I will post the proper working code later.)
-
@enceladus, thanks! Need to test this, but looks like all of the functions there are directly useable with Scripter.
-
So yes, you can use these with any of the
slide_x
scripts for example:import scene_drawing slide_value(view, 'y', 100, ease_func=scene_drawing.curve_bounce_out)
I could not find the functions documented anywhere, so here’s a reference:
-
Here is a simple demo example that I used for testing. I hope it is useful.
from scripter import * import ui import scene_drawing @script def custom_action(my_view): move(my_view, 200, 200) pulse(my_view, 'red') yield 1 hide(my_view) @script def custom_reverse_action(my_view): show(my_view) yield move(my_view, 100, 20) pulse(my_view, 'black') toggle = True def button_action(sender): global toggle s = sender.superview ease_func = scene_drawing.curve_sinodial #ease_func = scene_drawing.curve_ease_in #ease_func = scene_drawing.curve_ease_out #ease_func = scene_drawing.curve_ease_back_in #ease_func = scene_drawing.curve_ease_back_out l = s['label1'] title = sender.title if title == 'move': if toggle: move(l, 200, 200, ease_func=ease_func) else: move(l, 100,20, ease_func=ease_func) elif title == 'hide': if toggle: hide(l, ease_func=ease_func) else: show(l, ease_func=ease_func) elif title == 'rotate': if toggle: rotate(l, 30, ease_func=ease_func) else: rotate(l, 0, ease_func=ease_func) elif title == 'custom': if toggle: custom_action(l) else: custom_reverse_action(l) elif title == 'color': if toggle: slide_color(l, 'text_color', 'green') else: slide_color(l, 'text_color', 'black') elif title == 'count': if toggle: set_value(l, 'text', range(1,101), lambda c: f'count: {c}') else: set_value(l, 'text', range(100, 0, -1), lambda c: 'Text to be animated' if c == 1 else f'count: {c}') elif title == 'fly_out': if toggle: fly_out(l, 'down') else: move(l, 100, 20) elif title == 'font_sz': if toggle: slide_value(l, 'font', 40, start_value=20, map_func=lambda sz: ('Helvetica', sz) ) else: slide_value(l, 'font', 20, start_value=40, map_func=lambda sz: ('Helvetica', sz) ) toggle = not toggle v = ui.View(frame=(0,0,400,400)) l = ui.Label(text='Text to be animated', font=('Helvetica', 20), name='label1', frame=(100,20,200,100)) b1 = ui.Button(title='move', frame=(20, 300, 80,50), action=button_action) b2 = ui.Button(title='hide', frame=(120, 300, 80,50), action=button_action) b3 = ui.Button(title='rotate', frame=(220, 300, 80,50), action=button_action) b4 = ui.Button(title='custom', frame=(320, 300, 80,50), action=button_action) b5 = ui.Button(title='color', frame=(20, 350, 80,50), action=button_action) b6 = ui.Button(title='count', frame=(120, 350, 80,50), action=button_action) b7 = ui.Button(title='fly_out', frame=(220, 350, 80,50), action=button_action) b8 = ui.Button(title='font_sz', frame=(320, 350, 80,50), action=button_action) v.add_subview(l) v.add_subview(b1) v.add_subview(b2) v.add_subview(b3) v.add_subview(b4) v.add_subview(b5) v.add_subview(b6) v.add_subview(b7) v.add_subview(b8) v.present('sheet')
-
@enceladus, thanks again. Looks like something that I was thinking of doing, splitting out the demo from the main code, and having buttons to launch specific effects. Would you mind if I developed this further and included it in the repo?
-
Fell free to use whatever way you want. Anyway it is mostly your code.
-
@enceladus, in your
custom_action
, you are yielding 1 (second), which is not doing what it intuitively should, i.e. wait for 1 second after the previous actions have completed. Currently you need to have ayield
followed by theyield 1
.This confirms the misgivings I have had about the
yield wait
syntax. I would want it to work the way you used it. -
In the latest version
yield
now works as you would expect, i.e.:move(view, 100, 100) yield 2 pulse(view)
Also, scene_drawing easing functions are wrapped, so you can use them without separately importing them.
-
ok. Thanks.
-
This is way cool @mikael and really good extension @enceladus. Whenever I can spare the time I will try to extend it into a basic universal animation studio on all platforms. Sounds really challenging though but isn’t challenge the cradle of creativity?.
-
Check the first post for an image of scripter-demo.py. This additional script fulfills several roles:
- My testbed for checking that everything works
- Demo of all effects (click ”All”)
- ”Animation studio” where you can tweak the duration and easing functions to get the right effect
”Colors” demonstrates running an effect continuously and canceling it.
Code for the effects is shown as they are run, and can be easily copy-pasted elsewhere.
Tweaks to the core functionality include:
- Ending a script and starting the next one happen in the same call to
update
, removing any stutter caused by a no-op last call to a script. - Added some more effects like
rotate_by
to have feature parity with Scene animations - Added some more effects like
wobble
just for fun - Added some more easing functions - check the reference for the 21 alternatives.
-
Added a not-at-all-essential
roll_to
effect that takes into account the distance to be traveled and rotates the view an appropriate amount at the same time to make it look natural. Showcased below as a menu reveal effect.Also added Vector in the scripter.py, as it is often convenient for effects.