bartblast
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!

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! ![]()
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!
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.
Most Liked
bartblast
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.
bartblast
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 ![]()
bartblast
Video courses are coming soon in about 2-3 weeks. ![]()
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>
Popular in News & Updates
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #advent-of-code
- #elixirconf-us
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #performance








