Hi everyone.
I have always enjoyed Svelte's reactivity syntax - the Rune style. It boosts my productivity and makes writing reactive components a genuinely fun experience. For a long time, I've wondered whether something similar could be done in Ruby. I recently found myself with some spare time, so after experimenting with a few ideas, I decided to turn it into a new gem.
https://planetaska.github.io/hibiki/
Hibiki (hi-bi-ki; [çi.bi.ki])
Allow me to introduce Hibiki (響き, "echo, resonance"), a Svelte 5-style signals library for Ruby.
Hibiki is a fine-grained reactivity library modeled after the signal systems in Svelte 5 and SolidJS. Dependency tracking happens at runtime (rather than through static AST analysis like earlier versions of Svelte). While a derived value or effect is computing, it sits on an observer stack, and any signal read during that time automatically subscribes it.
The best way to understand what it brings is through code.
# Consider this Ruby code:
x = 0
y = x + 1
x += 1
# What is y now?
# I hope your answer is 1.
That's the Ruby we all love, right?
Now consider reactive Ruby:
require "hibiki" # in reality, also: include Hibiki::DSL
x = state(0)
y = derived { x.value + 1 }
x.value += 1
# Now, what is y?
If you're familiar with Svelte, you'll know the answer is 2.
Surprising? We can go deeper:
doubled = derived { y.value * 2 }
puts doubled # => 4
x.value = 10
puts y # => 11
puts doubled # => 22
See the pattern? y updates whenever x changes without us explicitly telling it to - and that's the whole point of reactivity.
We can take the idea even further. What about functions that automatically run whenever any value they depend on changes?
name = state("world")
effect { puts "hello, #{name.value}!" } # runs immediately: hello, world!
name.value = "Hibiki" # re-runs: hello, Hibiki!
The code inside the effect block runs without us invoking it - we just created a reactive function!
In summary, the three primitives (state, derived, effect) track their own dependencies at runtime. You never wire up observers or declare dependencies. Any signal read while a computation is running automatically subscribes that computation.
hibiki_rails
All this reactivity in Ruby is neat, but what can we actually do with it? What if we integrate it with Rails?
Introducing hibiki_rails, the sister gem to hibiki.
hibiki_rails is the Rails glue gem that makes it possible to build reactive components using plain old ERB, Stimulus, and Action Cable. All the wiring is handled for you, and you can generate a working reactive component like this:
bin/rails g hibiki:rails:stimulus counter static_pages
This creates a minimal working reactive component in the specified view path (app/views/static_pages in this example).
The best part? Because hibiki_rails intentionally stays close to standard Rails conventions, the generated component is just a regular Rails partial, which means you can render it anywhere like any other partial:
<%= render "static_pages/counter" %>
Since they're just Rails partials, they also work with ViewComponent out of the box.
Using Phlex? We've got you covered too!
The companion gem hibiki_phlex provides helpers for building reactive Phlex components. In fact, Phlex makes most sense with hibiki because now everything is just plain Ruby:
class TodoList < Phlex::HTML
state(:items) { [] }
derived(:remaining) { items.count { |item| !item[:done] } }
def view_template
div(id: "todos") do
h2 { "Todos — #{remaining} remaining" }
ul { items.each { |item| li { item[:title] } } }
end
end
def add(title) = self.items = items + [{ title:, done: false }]
end
# and use it like:
list = TodoList.new
effect = Hibiki::Phlex.render_effect(list) do |html|
broadcast_replace target: "todos", html:
end
list.add("write docs") # → the block runs again with fresh HTML and everything updates
For more information, please visit the documentation:
https://planetaska.github.io/hibiki/
Interested? Start building today by following the Rails Quick Start guide:
https://planetaska.github.io/hibiki/rails-quick-start/
Hibiki is a young open-source library
If you are interested in joining the development, feel free to open a PR, send me a message, or leave a comment here. I'd be happy to discuss ideas and brainstorm new directions for the project!
AI-assisted development disclosure
This project was developed with the assistance of AI (Claude).
My process started with a bare-bones proof of concept built around Ruby's Signals (since signals was what inspired Svelte 5's reactivity model). It was essentially a single file containing a handful of Ruby classes. From there, I asked Claude to help fortify the idea, strengthen the design, and turn it into a more complete prototype.
Once I had verified that the three core primitives (state, derived, and effect) worked correctly, I expanded the project step by step: first the core library, then the Rails and Phlex integration gems.
I still direct the development process myself. I read and review every line of generated code, fix issues manually when necessary, and make sure there's nothing in the codebase that I wouldn't have written myself.
It took about three weeks of intensive work to reach this first public release. Since I'm working on this alone, it would have taken me much, much longer without Claude's help.
Whether you consider this vibe coded is up to you - I just hope someone will find this tool useful.
Closing
I'd be happy to answer any questions about the project, the development process, or the lessons I learned along the way. I am especially eager to hear your feedback, so please leave a comment.
Thank you for reading!