Game Dev Hobbyist

A blog about my game dev hobby and various stuff.



Game Dev Hobbyist

A blog about my game dev hobby and various stuff.


AbstractContainer scene: res://addons/cardengine/container/abstract_container.tscn (source)
ContainerManager class: res://addons/cardengine/container/container_manager.gd (source)


Containers are a way to display multiple cards from a store with many options for the layout and animations. Where containers really shine is that they come with a UI which allows you to create them without coding.

Managing containers


To create a container press the "Create container" button. Fill in the ID and the name. The ID cannot contain spaces, can only contain a-z A-Z 0-9 characters and cannot start with a number. The name can be any non-empty string of characters.

Changing ID and name

The ID cannot be changed.

The name can be changed by double-clicking the container in the list.


To delete a container, select it in the list and press the "Delete container" button. You will have to validate the delete with the confirm dialog. Be careful, deleting a container is not reversible. Note that only the "private" part of the container is deleted, to completely delete your container, you have to also delete the corresponding folder res://containers/<container ID> manually.


You can open your container scene in the Godot editor by pressing the "Open container" button.

Edit containers

To start editing your container press the "Edit container", you will be presented with the following dialog window:

Important: *no* modification is saved until you press the "Save" button at the bottom of the dialog.

Layout tab

The layout tab is where you choose how cards are positioned in the container.

The following properties are common to both modes


Containers can follow 2 modes for their layout. The "Grid mode" which positions the cards in rows and columns. The "Path mode" which positions the cards along a path that you draw (see Customizing containers below).


You can choose which card face the container presents you by default.


When you turn on "Fixed width", cards will all have their width set to "Card width". Otherwise the card width is calculated to fit in the grid width or on the path length.

Horizontal spacing

Defines the spacing of the card on the horizontal axis as a ratio of the card's width. A value of 1 means cards will touch each other but without overlapping. A value below 1 means cards will overlap, example: 0.5 means cards will overlap by a half. A value greater than 1 means there will be space between cards, example: 1.25 means there will be a space a quarter the width between them.

The following properties are only applicable to the "Grid mode"

Vertical spacing

Same as the horizontal spacing but on the vertical axis.


In case "Fixed width" is on, there is the possibility cards will not fill all the container space. "Horizontal alignment" defines how cards are positioned horizontally in this case. "Vertical alignment" is the same but vertically.


It defines the number of columns the container will use to layout the cards. The number of rows being then defined by the number of cards divided by the number of columns rounded up. Example: with 10 cards and 3 columns, you will have 4 rows, the last one with only 1 card.

Expand containers

If on, the container will adjust its size so no cards is outside its boundaries. The container width will only expand if fixed width is on. This option is particularly useful when placing the container inside a ScrollContainer to activate the scrolling.

Interaction tab


You can deactivate interactivity for cards inside a container. It is mostly useful to create static card display that only need an idle animation.


When activated the focused card will be the only one to receive user inputs. This is useful when cards overlap and you don't want cards behind to gain focus.

Last card only

On interactive container you can tell that only the last card, usually the one on top, will receive user inputs.

Drag enabled

Enable the container to be a source of drag&drop actions.

Drop enabled

Enable the container to be a receiver of drag&drop actions.

FineTuning tab

The fine-tuning tab helps you add variation to your layout. You can adjust the position, scale and rotation independently but they all work in the same manner.

You can enabled/disabled them as needed.


In "Linear" mode the values are interpolated from the minimum at the first card to the maximum at the last card.

In "Symmetric" mode the values are interpolated from the minimum at the first card to the maximum in the middle and back to the minimum for the last card. Note that in case the number of cards is even, the middle is between 2 cards, meaning that no card will actually reach the maximum.

In "Random" mode each card receive a value picked randomly between the minimum and maximum.


A range is compose of two values, a minimum and a maximum. In case of position and scale the value is a 2D vector to treat the horizontal and vertical value independently. In case of the rotation the value is given in degree.

Note: values are relative to the values set by the layout, position and rotation will be added and the scale will be multiplied.

Aspect ratio (scale only)

In "Keep" mode the horizontal scale is applied to the vertical scale.

In "Ignore" mode the horizontal and vertical scales are calculated independently.


The transitions tab has to do with changes to the layout and how to animate them. Currently CardEngine supports 3 types of change:

  • On layout change: is when a card is already in the container and a change to the layout is triggered, during event like a resizing, sorting or filtering.
  • On card added: is when a card was not present previously on the container and has to be added to it, happens when cards are added to the store or filters are removed.
  • On card removed: is when a card was present in the container but no-longer is, it happens when cards are removed or filters are added.

Note: the card added and removed transition rely on an external node to function see Customizing containers below.


Defines the duration of the transition in milliseconds.

Type and Easing

Defines the curve the transition will follow to smooth out the movement (see this cheat sheet for reference).

Note: transitions are applied to position, rotation and scale all at once.


The animations tab is about how the container will animate its cards based on interaction with the mouse.


You can choose from the list the one animation you want. If you don't want any animation, just select "None".

It is also possible to make some adjustments to the layout to help make your animations more predictable especially in the case you made some fine-tuning.


Defines when this adjustments will take place. Currently it can be "On focused" (mouse hover) or "On activated" (mouse pressed). If "On focused" is selected adjustments will remain through the active phase too.

Adjustments can made to the position, scale and rotation. They all function on the same model.


"No change"  means no adjustment will be made.

"Relative change" means the adjustment will be added (position, rotation) to, or multiplied (scale) with, the value set by the layout.

"Absolute change" means the adjustment will totally overwrite the value set by the layout.


For position and scale the horizontal and vertical value can be adjusted independently.

For the rotation the value is in degree.

Customizing containers

As seen above you can already do a lot from the edit dialog window, but there is still some tweaks to make by editing the container scene. You have two choices on how you customize:

  • By editing the public container scene that you can find in res://containers/<container ID>
  • By editing an instance of the scene when you add your container in another scene

Card Visual (mandatory)

Use this property to set the card you want to be used in the container. This must be a scene inheriting from AbstractCard (for more details).

Drag Widget

Use this property to set the widget that can be used instead of the card in a drag and drop interaction. This must be a scene inheriting from Control (example: res://containers/card_list/card_list_drag.tscn source).

In Anchor

Use this property to set a node that will be used for the added card transition (see Transitions above). The node can be a Node2D or a Control. Its position, scale and rotation will be used to define the initial transform for newly added cards.

Out Anchor

Same as In Anchor but for removed cards.

Note: due to limitation in the Godot API, the in and out anchors should be siblings of the container so they have the same origin. This problem is most notable for the position, if the anchors and containers are not siblings, there is a risk that the cards appearing, or disappearing, would not do so at the intended position.

In case you have setup your container in "Path mode", you have to create a path for your cards to follow. To do so, create a new Curve2D for the "Curve" property of the "CardPath" node of your container scene. You can now use the Godot Editor tools to draw your path:

Note: for you cards to follow the path as drawn on screen, make sure the CardPath transform is at its default values. Tips: move the points of the path and not the whole path.

Adding card to containers

The last step to have a fully functioning container is to add cards to display. This is the only part where you need to write some code. Cards in containers come from stores. Here an example from the demo, that is used to display 3 cards at the top-left of the main menu, the code is added to the menu screen scene _ready function:

var db = CardEngine.db().get_database("main")
var q = Query.new()
var store = CardPile.new()

var cards = q.from(["rarity:common"]).execute(db)
store.populate(db, cards)

Quick explanation

  1. We retrieve the "main" database
  2. We create a database query
  3. We create a store
  4. We retrieve all the "common" "rarity" cards from the db
  5. We use the result to populate our store
  6. We shuffle the store to randomize the order of the cards
  7. We keep 3 cards
  8. We set the store to be the container store

For a more in depth explanation on stores and queries click here.