Cheatsheet¶
PyperCard is an easy and simple GUI framework with a focus on beginner Python programmers. This page contains all the technical information you need in one place. You should use it for reference purposes. If you’d like to learn more about PyperCard please consult the tutorials.
Installation¶
PyperCard runs on top of PyScript - a browser based Python platform.
The quickest way to get going is via a free (but limited) account at PyScript.com:
Create a new project.
Update the project’s
pyscript.toml
file sopypercard
is listed as a dependency:
packages = ["pypercard", ]
Create your app and define transitions, via Python, in the
main.py
file.The
index.html
file can be used to define how your cards look via several hiddentemplate
elements.
Alternatively, just look at the example projects to see how to organise an app.
Core concepts¶
PyperCard’s core concepts are:
An app contains a stack of cards.
A card represents a screen in your app.
A transition allows users to move between cards in a meaninful way.
If the app is the global context, then each card fulfils a specific role or function within the application. Cards define what the user sees at any given time.
When a transition is activated (for example, because a user has clicked a button), functions containing business logic are called, state is changed via the app’s key/value datastore (more on this below) and the next card is indicated.
The App¶
The App
class represents a card based application.
This object encapsulates state (as a key/value DataStore
instance), a stack
of Card
instances, and registering transitions.
The app’s datastore
is a shim around the browser’s localStorage
expressed
as a Python dict
. Sometimes, because of the browser’s security policy, it’s
not possible to get access to localStorage
and so a standard Python dict
is
used instead (although, as a result, state is not preserved between page
reloads).
For an app to work, it needs a stack of cards and some transitions. Each card
has a name, unique within the application context. A list of Card
instances
can be passed in when the app is instantiated, or cards can be added later, on
the fly. If no cards are passed in at instantiation, the app will query the DOM
for template
elements, whose attributes and content it will use to create its
stack.
Transitions are simply decorated Python functions that will be called with the
instance of the app, and the Card
instance representing the card that
generated the event that fired the decorated transition function.
Other app-wide functions (such as playing or pausing sounds) are methods of this class. To add your own app-wide functions, create a sub-class of this one.
Once created, start the app with a given card, or else the app starts with the very first card added to its stack.
The application is rendered into the DOM via a pyper-app
element.
A Card¶
A Card
instance defines what is presented to the user. The app ensures only
one card is displayed at any time.
Every card has a name
that is unique within the current application, and a
template
that can either be a string passed in at instantiation time or else
the card will look for a template
tag in the DOM with an id
that matches
the card’s name, and whose content and attributes will define how the card
looks and behaves.
Cards may also have optional auto_advance
and transition
attributes for
transitioning to a target card after a given period of time.
Cards are rendered from the template
in the show
method. The first time
show
is called it creates a pyper-card
HTML element for the app to
insert into the DOM.
Bespoke behaviour for rendering can be defined by the user. This should
be passed in as the optional on_show
argument when initialising the
card. It will be called, at the end of the card’s show
function, but
before the element to insert into the DOM is returned to the app. The
on_show
function is called with the same arguments as a transition
function: a reference to the app and the current card.
The hide
method hides card’s HTML element, but leaves it in the DOM.
Card’s can optionally take some action each time a card is hidden using the
on_hide
method. The on_hide
method is called with the same arguments as
a transition function: a reference to the app and the current card.
The convenience functions called get_by_id
, get_element
and
get_elements
return individual or groups of matching HTML elements
rendered by this card, given a valid id or CSS selector (comments attached
to the functions explain the specific behaviours).
Cards can optionally define the nature of their background, via the
background
and background_repeat
attributes. The background
should
either be a valid CSS color
or a URL to an image. If the background
is
an image, the background_repeat
flag will indicate if the image will
fill the whole screen or repeat in a tiled fashion (the default is to
fill the whole screen).
The attributes of a template
element in the DOM will map directly to the
attributes of the related Card
instance. Thus, background
, auto-advance
and other HTMLElement attributes set the equivalent methods on the instance.
A further convenience includes detecting a transition
attribute on an HTML
button
element within the card’s template. If, when the card is visible to
the user, the button is clicked, it will automatically transition to the name
of the card given as the value of the transition
attribute.
Transitions¶
Transitions are simply Python functions that react to events, and tell the app what to do next.
If a transition returns a string, and the string contains the name of a card in
the app’s stack, the app will hide the current card and display the card
referenced in the result of the function. If the transition function returns a
None
the app will keep the current card on the screen.
A transition function always takes the same arguments, a reference to the
current app (so you have access to getting/setting state or other capabilities
provided by the App
class), and the Card
instance that dispatched the
event. You can, optionally, retrieve the event object created by the browser
that represents activity that resulted in the function call.
To define a transition function you need to use a decorator provided by your app.
my_app = App()
@my_app.transition("my_card", "click", "button_id")
def my_transition(app, card, event):
"""
A decorated transition function for the "my_card" card.
When the HTML element with the `id` "button_id" is "click"-ed then the
function will be called.
"""
... do business logic here...
return "next_card"
This just adds a transition to the app’s underlying state machine.
The first argument can be either a string of the name of the target card, or a list of target card names.
The second argument is the name of the event, as dispatched by the browser, e.g. “click”.
The third argument is the unique id
attribute of the target element within
the referenced card[s], that will dispatch the event.
Finally, you can replace the id
argument with a named query
argument, as a
way to provide a valid CSS query to match elements within the referenced
card[s], that will dispatch the event.
DataStore¶
Every app has a datastore
, an object that behaves like a Python dict
for
storing app state.
Usually, this is a Pythonic shim around the browser’s localStorage
object.
However, sometimes due to the browser’s security context, the localStorage
object is not available. In this case, a regular Python dict
is used, but
with the disadvantage that state isn’t retained between page reloads.
For more information about the characteristics of the localStorage
object
please
read this documentation.
Other Stuff¶
The PyperCard framework is very much “early stage” and alpha quality, despite such a lot having already been written.
More coming soon.