a family-friendly virtual escape room written in PETAL

Hi all! I wanted to write to say THANK YOU! I just developed an interactive virtual escape room using PETAL (and obviously relied heavily on this forum’s responses when I had problems).

I am not going to spoil the intricacies of the puzzles but the escape room basically has 4 people working together on interactive puzzles using an integrated video chat where they have different controls and all have to work together to solve it. It is primarily targeted for first-time puzzlers but is fun for experienced puzzlers too.

This was my first time ever building with Tailwind, Alpine or Liveview (and for the most part Phoenix too :)) as well as my first time building/using a GenServer (as a puzzle state machine).

TLDR; There were a bunch of little nuances but overall it was a lot of fun and it’s hard to go back to Phoenix once you’ve been using Liveview. Also see below if you want to try it.

Some pros and cons:


  • I LOVE the Liveview/Pubsub models. It made it so easy to have Live interactive sessions where everyone could see each other’s updates in realtime. I did have to use channels for one section with heavy interactions, but overall I kept most of it to Liveview and it thrived.
  • Liveview is really fun even without multiplayer interactions. I love how simple it is to change things and relieved I did not need to work in React.
  • rocks for deployment and the founders were great to chat with as well.
  • I still love Phoenix Channels too. Super easy to set up and manage.
  • Kaffy is awesome for an admin tool. I got it up and running in 15 minutes.
  • Ecto is very nice (but everyone here knows that already).


  • The GenServer worked well but it felt like a lot of overhead to set up w/supervisors and build API structure for (since you have to build functions both for client and server). Don’t know if there are faster ways to do it and it was my first time too so maybe it gets easier?
  • JS in liveview components/sub-pages. I used both liveview components and sub-liveview pages. The big challenge was not being able to launch JS when those were loaded. I got around it by loading the JS in the Alpine X-init. It felt a bit hacky but I did not know another solution.
  • I still do not have a great way to do pipes with conditions (as in add this to the socket assigns if condition X is met). I built a bunch of sub-functions and piped to them but wish the language had a simple pipe-if.

Mostly I wanted to say thank you! This escape room would have been much harder without this community. And the fun I had with Liveview has me looking at using it for other projects too.

If you like escape rooms or want to try one, I have set up a temporary link for members of this group to try it for free.

You’ll need a team name and a team of 4 people with laptops at different locations. It has a private leaderboard for this group so maybe we can have an elixir-forum competition?

NOTE: This is a normally paid room so please do not share the link outside of this forum.

Also if anyone has questions about how I built this or any other thoughts, please comment below!


Your post is very motivating! Thanks for sharing.


This forum is indexed by Google :wink:

Elixir 1.12 has introduced the then function, which lets you do something like this:

%{room: %{id: 1, doors: [%Door{id: 1}]}
|> then(fn room ->
  if Enum.any?(room.doors) do
|> start_puzzle()

or with pattern matching:

%{room: %{id: 1, doors: [%Door{id: 1}]}
|> then(fn
  %{doors: []} = room -> create_door(room)
  room -> room
|> start_puzzle()

Just letting you know it is possible to “pipe into an if expression”.

Anyway, congratulations! i will check out your awesome creation when I find 3 teammates.


Yeah, I know :). That’s why I said the link was temporary. Once google indexes this post, I’ll disable it. Ideally I could set a parameter to turn off indexing on this altogether.

Oh cool! I was hoping they could somehow expand guards so you could have something like:

|> assign(:foo, when foo != nil

Just makes it more readable.

I would abstract the anonymous function to a private function, thus making the pipeline much more readable, provided the private function is named properly :slight_smile:


I’m also on my first real project with Elixir, and I feel the same. Language, ecosystem, community are just great.

I’d like to give your game a try, but I can’t just get three people only to try something out. Is there a way to play alone to take a look?

Each player has different links so you could potentially get a feel by opening each different player in a different browser window but it would be pretty difficult to finish that way. The most fun way would be to just ask other people here to form a team!