This page includes several examples that can be found in the code included with my Easy Blinking for Ren’Py tool, found on itch.io below. These examples require the tool to work.
They are included here for reference.
Example 1 – Direct EasyBlink declarations
## This example shows how you can directly declare blinking attributes using
## the EasyBlink class. It's useful if you only want one or two blinking
## attributes, or if you aren't using a layered image (so you can't use
## the layered image format function in the extras file).
layeredimage agustina_not_auto:
always "agustina_base"
## Note: You should set up the default values of EasyBlink at the top of
## easy_blink.rpy to be the values you use most often. Then you can omit
## a lot of repeated arguments from your declarations. These attributes
## assume the following defaults:
## blink_framerate = 0.04
## numbered = False
## reverse = False
## start_no_num = False
## automatic_blink_frames = []
group eyes:
## Instead of an image like "agustina_eyes_normal", you will use the
## EasyBlink class to declare the blinking attributes.
## See the top of easy_blink.rpy for explanations on each property.
## The only required parts are the path and img properties.
## These are used as follows:
## path : The path where the eye images are found, so the image path
## can be put together with path + img substitutions. It should
## include the substitution {img} which will be replaced with
## the image name. e.g. "characters/eileen/{img}.webp"
## or an auto-declared one like "eileen_eyes_{img}"
## If numbered=True, it should also include a {num} substitution
## which will be replaced with the number of the image.
## e.g. "characters/eileen/{img}{num}.webp"
## or an auto-declared one like "eileen_eyes_{img}{num}"
## If it doesn't include any {img} substitutions, then your
## mid_blink_frames will need to be direct image paths too.
## img : The name of the first frame of the animation/the open eye
## image. It's substituted in as the value for {img} in the path.
## e.g. "happy_e"
## Not used if `path` does not have an {img} substitution.
attribute normal default EasyBlink(
path="agustina_eyes_{img}", img="normal",
## This will go normal->semi->closed->semi->normal
## The mid-eye frames are also substituted in for {img} in the path.
## So this finds "agustina_eyes_semi" and "agustina_eyes_closed"
## along with the open eye image, "agustina_eyes_normal"
reverse=True, mid_eye_frames=["semi", "closed"],
)
attribute cry EasyBlink(
path="agustina_eyes_{img}{num}", img="cry",
## These images use a numbering scheme, from 0-2
## agustina_eyes_cry0, agustina_eyes_cry1, agustina_eyes_cry2
reverse=True, numbered=True,
)
attribute surprised EasyBlink(
path="agustina_eyes_{img}", img="surprised",
## This attribute lacks the "semi" frame, so it goes from open
## to closed with no other in-between frames.
mid_eye_frames=["closed"],
)
attribute surprised2 EasyBlink(
## The path can also be a direct image path with no {img}, in
## which case the mid_eye_frames should also be direct image paths.
## If you're using numbered frames, you still need to include
## the {num} substitution in the path, but the mid_eye_frames
## won't matter (since they aren't used for numbered animations).
path="easy_blink/agustina_eyes_surprised.png",
mid_eye_frames=["easy_blink/agustina_eyes_semi.png",
"easy_blink/agustina_eyes_closed.png"],
## Note that you can also use image names declared with the `image`
## statement or through Ren'Py's auto image declaration rules e.g.
# path="agustina_eyes_surprised",
# mid_eye_frames=["agustina_eyes_semi", "agustina_eyes_closed"],
)
attribute side_eyes EasyBlink(
path="agustina_eyes_{img}", img="side_eyes",
## This attribute gets an automatically generated mid-blink frame,
## since it's looking to the side. The open eye image has all
## transparency at the bottom trimmed away so that the eyes are
## at the bottom of the image. In this case it'll get squished
## down to 85% (0.85) of its usual height to provide an extra frame
## between "open" and "closed".
automatic_blink_frames=[0.85],
## The "semi" frame is omitted because we're auto-generating it,
## above.
mid_eye_frames=["closed"],
## We'll linger for a shorter time on the mid-blink frame and longer
## on the closed and open eye frames.
blink_framerate=[0.04, 0.02, 0.04],
)
attribute semi EasyBlink(
path="agustina_eyes_{img}", img="semi",
## The "semi" frame is omitted because the eye already
## is semi-closed.
mid_eye_frames=["closed"],
)
## This is just a regular, non-blinking attribute
attribute closed "agustina_eyes_closed"
attribute normal_dissolve EasyBlink(
path="agustina_eyes_{img}", img="normal",
reverse=True, mid_eye_frames=["semi", "closed"],
## This is the same as normal eyes, but with a dissolve transition
## between each frame. You can either provide just a transition,
## as seen here, or a list of transitions, in which case you need
## at least one transition for each frame (including a transition
## between the last and first frames when it loops).
## If reverse=True and you provide a list of transitions, the
## transitions will be reversed as well (e.g. so the transition
## between mid-to-closed is the same as the one for closed-to-mid),
## and you need one less than the number of frames.
transitions=Dissolve(0.4),
## The transition always takes the full amount of time to play out,
## so 0.4 seconds dissolve from one frame to another, and then it
## waits on that frame for 0.1 seconds before starting to dissolve
## to the next.
blink_framerate=0.1,
)
## These two attributes show two different ways of declaring the same
## thing. This is an expression with a "startup animation", where the
## character's eyes go wide for a moment before they look to the side
## and loop blinking.
attribute short_surprise EasyBlink(
path="agustina_eyes_{img}", reverse=True,
## This declaration uses the special `sequence` argument instead
## of img, mid_eye_frames, blink_framerate, and transitions.
## It takes a list of tuples, each with the following format:
## (img, <time>, <transition>)
## img : Required. The name of the image to use, provided in the
## same format as mid_eye_frames.
## <time> : Optional. The amount of time to wait on this frame.
## If omitted, it defaults to blink_framerate.
## <transition> : Optional. The transition to use when moving to
## the next frame. If omitted, it defaults to None.
sequence=[("normal", 0.25, Dissolve(0.1)),
("surprised", 0.5, Dissolve(0.3)), ("side_eyes", 0.2),
("side_eyes", 0.04), ([0.85], 0.03), ("closed", 0.04)],
## You might have noticed "side_eyes" in here twice - this is
## so the looped blinking doesn't have a long pause on the first
## frame, but we also want to linger on side_eyes for a moment
## after the surprised eyes.
## There's also a tuple that starts with [0.85] - this is
## interpreted as an automatic_blink_frames argument. It will
## use the eye image immediately before it (the side_eyes) at
## 85% of its usual height.
## Lastly, this says that the actual blink looping starts at frame
## 3, aka on ("side_eyes", 0.04) - remember that indices start at 0.
loop_start_frame=3,
)
## This declares the same thing as earlier, but through separate
## arguments. Both do the same thing, so it's up to you which format
## is easier to use.
attribute short_surprise2 EasyBlink(
path="agustina_eyes_{img}", img="normal",
reverse=True, mid_eye_frames=["surprised", "side_eyes", "side_eyes",
[0.85], "closed"],
blink_framerate=[0.25, 0.5, 0.2, 0.04, 0.03, 0.04],
transitions=[Dissolve(0.1), Dissolve(0.3), None, None, None],
loop_start_frame=3,
)
Example 2 – Format Function (automatic)
The following example uses the format function which is included in the extra paid file of Easy Blinking. It is useful if you’re planning your layered images around blinking, or if you’re following a naming convention for your images which includes the attribute name (and especially if you’re relying on Ren’Py’s default format function).
layeredimage agustina:
## Here you will provide the layered image with a custom format_function.
## It takes the following special arguments:
## which_group : list
## A list of strings giving the names of the groups to apply
## blinking to. By default, this is ["eyes"] so it will only apply
## to attributes under `group eyes`.
## format_function : callable
## If you already had a format function for your layered image, pass
## it in as the format_function argument to this class. If not, you can
## ignore this argument.
## no_blink_attrs : list
## A list of strings giving the names of the attributes that are in the
## which_group groups but shouldn't be animated (e.g. you wouldn't want
## closed eyes to blink; they're already closed).
## e.g. ["closed", "nervous"]
##
## It also takes all the same arguments as EasyBlink, which will be used
## when creating the blinking images - this includes the `path` argument
## which should include {img} and {num} as necessary e.g.
## path="characters/eileen/{img}{num}.png"
##
## By default, the attribute name is substituted in for {img} to get the
## first frame of the blink e.g. if you had `attribute happy_e` then using
## the path "characters/eileen/{img}{num}.png" would look for
## "characters/eileen/happy_e0.png" for the first frame of the blink if it's
## numbered and "characters/eileen/happy_e.png" if it's not.
##
## The `path` argument can also be a dictionary, where the key is a name of
## the group in which_group and the value is the path to use. For example:
## path=dict(eyes="characters/eileen/eyes_{img}{num}.png",
## glasses_eyes="characters/eileen/glasses_eyes_{img}{num}.png")
## This is useful if you have different naming conventions for each group.
##
## See below for how to adjust the arguments for individual attributes also.
format_function EasyBlinkFormat(
# path="easy_blink/agustina_eyes_{img}{num}.png",
# path=dict(eyes="easy_blink/agustina_eyes_{img}{num}.png"),
which_group=["eyes"], no_blink_attrs=["closed"],
numbered=False, mid_eye_frames=["semi", "closed"],
reverse=True, blink_framerate=0.04)
## Now you can declare the rest of your layered image. For simplicity,
## this one only has a base and a group for the eyes.
always "agustina_base"
## Note: You can't use `auto` here because that skips the format function,
## so you wouldn't get any blinking (just static images).
group eyes:
## You will still set up default attributes as usual.
attribute normal default
## This attribute won't be animated because it's in the no_blink_attrs
## from earlier.
attribute closed
## This is a standard attribute.
attribute surprised
## Instead of an image path (e.g. `attribute cry "agustina_cry"`),
## if you use a dictionary then those arguments will be passed to the
## EasyBlink. They will be used in preference to what you set up in the
## format_function.
attribute cry dict(numbered=True)
attribute side_eyes dict(automatic_blink_frames=[0.85],
reverse=False, mid_eye_frames=["closed"]
)
attribute semi dict(mid_eye_frames=["closed"])
## This attribute has a startup animation before looping on frame 3.
## It also uses a few transitions and different timing, so it's provided
## as a sequence.
attribute short_surprise dict(
sequence=[("normal", 0.25, Dissolve(0.1)),
("surprised", 0.5, Dissolve(0.3)), ("side_eyes", 0.2),
("side_eyes", 0.04), ([0.85], 0.03), ("closed", 0.04)],
loop_start_frame=3
)
## This is a normal eyes attribute that includes a transition between
## each frame.
attribute normal_dissolve dict(img="normal", transitions=Dissolve(0.4))
Example 3 – Format Function (pre-existing images)
The following example uses the format function which is included in the extra paid file of Easy Blinking. It is useful if you already have a layered image set up and you want to add blinks to it without changing the existing image paths, especially if they don’t have a consistent pattern with the attribute names.
layeredimage agustina2:
format_function EasyBlinkFormat(
no_blink_attrs=["closed_e"], which_group=["expressions"],
numbered=False,
mid_eye_frames=["easy_blink/agustina_eyes_semi.png",
"easy_blink/agustina_eyes_closed.png"],
blink_framerate=0.04)
always "easy_blink/agustina_base.png"
group expressions:
attribute normal_e default "easy_blink/agustina_eyes_normal.png"
attribute closed_e "easy_blink/agustina_eyes_closed.png"
attribute surprised_e "easy_blink/agustina_eyes_surprised.png"
## Like before, you can use a dictionary to pass in arguments to the
## EasyBlink object. This dictionary also takes a key called "path",
## which will be used as the path argument to EasyBlink. In most cases,
## the path argument is what you used to have for the image path.
##
## This path can include the {img} and {num} substitutions - if present,
## img will be replaced by the name of the attribute, and num is used
## for the numbered frames.
attribute cry_e dict(path="easy_blink/agustina_eyes_cry{num}.png", numbered=True)
## Note that here and in the format_function declaration the
## mid_eye_frames are all full image paths, since these paths
## aren't using an {img} substitution.
attribute side_e dict(path="easy_blink/agustina_eyes_side_eyes.png",
automatic_blink_frames=[0.85], reverse=False,
mid_eye_frames=["easy_blink/agustina_eyes_closed.png"],
)
attribute semi_e dict(path="easy_blink/agustina_eyes_semi.png",
mid_eye_frames=["easy_blink/agustina_eyes_closed.png"])
## This attribute has a startup animation before looping on frame 3.
## It also uses a few transitions and different timing, so it's provided
## as a sequence.
attribute short_surprise dict(
path=None,
sequence=[("easy_blink/agustina_eyes_normal.png", 0.25, Dissolve(0.1)),
("easy_blink/agustina_eyes_surprised.png", 0.5, Dissolve(0.3)),
("easy_blink/agustina_eyes_side_eyes.png", 0.2),
("easy_blink/agustina_eyes_side_eyes.png", 0.04),
([0.85], 0.03),
("easy_blink/agustina_eyes_closed.png", 0.04)],
loop_start_frame=3,
)
## This is a normal eyes attribute that includes a transition between
## each frame.
attribute normal_dissolve dict(path="easy_blink/agustina_eyes_normal.png",
transitions=Dissolve(0.4))