Hologram v0.5.0 released!

I’m excited to announce Hologram v0.5.0, a major evolution of the full-stack Elixir web framework! This release brings massive performance improvements - we’re talking execution times improved from milliseconds to microseconds in core client-side operations, making it fast enough for real-time interactions like mouse move events.

Key highlights:

  • Complete bitstring rewrite with ~50x rendering speed improvements!
  • Comprehensive session and cookie management
  • Live reload functionality for enhanced DX
  • Incremental compilation (2x-10x faster builds)
  • New pointer and mouse move events
  • HTTP-based transport layer
  • CRDT support for future distributed features

Full release notes: Hologram v0.5.0 Released! - Hologram

Check out the SVG Drawing Demo that showcases smooth, responsive drawing using the new pointer move events - it really demonstrates the performance leap!

svg-drawing-demo-600

With over 950 commits since v0.4.0, this release delivers significant architectural enhancements while maintaining the unique developer experience that makes Hologram special.

Special thanks to my current GitHub sponsors: @D4no0, @Lucassifoni, and @sodapopcan! :folded_hands:

:purple_heart: Support Hologram’s development: If you’d like to help accelerate Hologram’s growth and make releases like this possible, consider becoming a GitHub sponsor. Every contribution helps dedicate more time to new features and community support!

:open_mailbox_with_raised_flag: Stay in the loop: Don’t miss future updates! Subscribe to the Hologram Newsletter for monthly development milestones, ecosystem news, and community insights delivered straight to your inbox.

30 Likes

:exploding_head: The svg drawing demo looks hella slick & hella cool! I would love to see the repo, if possible? It would force me to actually check out hologram for real (dabbled just a bit when it came out). :sweat_smile:

curiosity killed the cat but satisfaction brought it back :grinning_cat_with_smiling_eyes:

1 Like

Sorry if this was asked before, but do you plan to make hologram easily integrate with a LV project?

I’m very interesting in testing hologram out, but it is hard to justify the time to do that now since I don’t have a new project to use it, and at the same time, I don’t plan in rewrite all my LV projects in Hologram. So, having a way to easily integrate it with a LV page (maybe a way to add hologram components or something like that? Dunno) would be amazing and probably open doors to easily solve lateny critical parts to a LV project.

3 Likes

I have already suggested something like that, but it was not accepted. Also looks like there would be no support for :for and siblings, so you have to write the templates in Svelte-like syntax. For me this is one more important as in complex components I don’t want to have “half” of the indentation levels to be added by control flow (like if, for etc.) …

What I’m personally looking for is some way to communicate with page asynchronously. Looks like in the medium-term goal there would be:

  • Component Subscription DSL - Create a DSL for integrating with Phoenix PubSub for real-time updates.

Preferably I would like to use send/2 and Process.send_after/3 depending on a case. Simply everything that happens in background, but affects the rendering like bot moves every pre-configured time, sending data from Repo.stream without querying all the rows or paginating them, next background music event and many, many more …

1 Like

Congrats Bart! Looking great.

1 Like

Congratulations on the release. :clinking_glasses:

One thing that I’m taking away from the changelog is that it might be time to start taking some parts of Hologram and release them as individual specialized libraries, maybe. I’m periodically taking a look and there seems to be some mighty useful Elixir pieces in there.

I’m not saying this to give you homework. But it might help adoption.

2 Likes

Very cool! I would be curious about the journey of what went into optimizing the performance of Hologram.

1 Like

That could be done anytime. If author decides it should be done right before 1.0.0 release. I believe there are too many important parts that blocks people from using Hologram right now. We should rather allow the author focus on them.

1 Like

I disagree with this. The goal should be something like JSX where there is no template syntax at all and the templates are actually constructed with JS (with the syntax extended to make it look nicer). The :if/:for syntax, which afaik was a hack to make slots work, was a huge step backwards in this respect for Phoenix. The original eex/heex “templates” are actually full Elixir with text/html interspersed and thus far more powerful.

Templating languages are always degenerate. As a simple example, why is there no :case attribute? The case construct spans (possible) elements, so it doesn’t even make sense as an attribute. The control flow is a higher level construct than an individual element and can’t be constrained to one. It’s a mistake to go down this path at all.

It’s unfortunate because case is one of Elixir’s best features and I strongly favor it over if, even in heex.

With that said, it seems like Hologram’s templates are in fact actually templates rather than code, so that’s not any better if so.

(Incredible work on the release BTW, that’s a lot of commits!)

Video courses are coming soon in about 2-3 weeks. :slight_smile:

The demo is a part of the website code which is currently private, but here’s the most important code:

init/3 (state initialization) and actions (event handling):

def init(_params, component, _server) do
  put_state(component, drawing?: false, path: "")
end

def action(:clear_canvas, _params, component) do
  put_state(component, drawing?: false, path: "")
end

def action(:draw_move, params, %{state: %{drawing?: true}} = component) do
  new_path = component.state.path <> " L #{params.event.offset_x} #{params.event.offset_y}"
  put_state(component, :path, new_path)
end

def action(:draw_move, _params, component) do
  component
end

def action(:start_drawing, params, component) do
  new_path = component.state.path <> " M #{params.event.offset_x} #{params.event.offset_y}"
  put_state(component, drawing?: true, path: new_path)
end

def action(:stop_drawing, _params, component) do
  put_state(component, :drawing?, false)
end

and the most important part of the template:

(...)
  <button $click="clear_canvas" class={Button.class(:md)}>Clear</button>
</div>
<svg 
  class="bg-[#0F1014] cursor-crosshair border border-[#363636] rounded w-full h-[70vh]"
  style="touch-action: none;"
  $pointer_down="start_drawing"
  $pointer_move="draw_move"
  $pointer_up="stop_drawing"
  $pointer_cancel="stop_drawing"
>
  <path d={@path} stroke="#C2BBD3" stroke-width="2" fill="none" />
</svg>
6 Likes

Hologram can be used alongside LiveView in the same Phoenix application. You can have some pages running in LiveView and others in Hologram - they can coexist peacefully.

However, I don’t plan to work on direct Hologram/LiveView integration (like embedding Hologram components within LiveView pages or vice versa). This would introduce significant complexity and several drawbacks, including maintenance burden, architecture lock-in, conflicting paradigms, performance overhead, and others.

If you need to stick with LiveView for any reason (time constraints, existing codebase, etc.), you can always gradually migrate specific pages to Hologram when it aligns with your project’s requirements. This approach gives you the flexibility to use both frameworks without the complexity of trying to make them work together. Additionally, I plan to start working on a companion UI components library soon, which should significantly reduce the time investment needed to build interfaces with Hologram and make migration easier.

9 Likes

Random implementation detail, but I’d like to make a library for transpiling regexes from Elixir → js and Elixir → Postgresql at some point, that would be a subset (a growing subset over time) of Elixir’s regex capabilities. Might be useful when you get to =~ operators etc.

3 Likes

I can confirm that all of these use cases will be supported through either the planned subscription DSL or by sending messages directly to specific component actions via component ID, session ID, or connection ID.

1 Like

Thanks man! :slight_smile:

1 Like

Thank you! :slight_smile: I can see the appeal of extracting parts of Hologram into separate libraries, but I don’t think it’s the right time. The scope of Hologram is massive - it’s essentially Phoenix + LiveView + Surface + ElixirScript all rolled into one. Right now, I can focus on code that’s specifically tailored to support the framework’s goals, which allows me to move much faster.

Extracting libraries at this stage would significantly slow down development and potentially create architectural constraints, plus add additional overhead from managing the maintenance of such libraries. I’d rather get the core framework solid first, then consider what pieces might make sense as standalone libraries.

That said, I appreciate the suggestion and it’s definitely something I’ll keep in mind for the future!

5 Likes

The key insight was that every microsecond matters when you’re building a framework that needs to handle real-time interactions, render at least 60 FPS, and work with transpiled code using boxed types. I systematically profiled and optimized each layer - from the lowest-level bitstring operations up through the highest-level user interactions.

For profiling and benchmarking, I used a multi-tool approach:

  • Benchee for comprehensive Elixir performance testing
  • Custom JavaScript benchmarking scripts using process.hrtime() for precise timing
  • Chrome DevTools Performance Profiler for detailed client-side analysis

The JavaScript JIT compilation made it even more tricky, because you’ll see much different results for cold vs warm vs hot code. For the Elixir part, I was mainly optimizing the compiler, so the tricky part was balancing different project conditions - e.g., different characteristics depending on the call graph structure, module complexity, and compilation patterns.

It’s been quite a journey! The performance improvements were the result of countless hours of profiling, benchmarking, and iterative optimization. It was a very repetitive process, but strangely satisfying when you managed to squeeze out performance gains here and there :wink:

7 Likes

Hello and congratulations for this release ! I did not have the time yet to actually use Hologram, but I’m fully positive about your direction and vision.

Do you see anything that would block hot-loading Hologram modules at runtime in prod ?

From the docs, I don’t see things that would prevent that.
I see that the generated JS goes to priv/static/hologram, but this can happen at runtime too.

I’m not sure if I can recommend Hologram for prod. It’s definitely an amazing project with a brilliant future, but comparing to other solutions it lacks too many features and you would end up with a project that you can’t fix unless you wait for a next release. I would suggest to study docs and if you think that your project would need at least one missing feature then don’t rush into it too soon.

That’s said I fully recommend learning it and working on pet projects. I believe that it may become a really popular solution in future, but it needs more feature-complete release. Make sure you double check Roadmap before you decide to rush with it into prod as frustration here would be a huge loss for a project with such a promising future …

Thanks for your consideration. I would use it in a production setting, but for non-user-facing things (well, I would be the user), that I could easily port to Liveview if my interests diverged from Hologram’s.

2 Likes