Skip to content

BrigBryu/ember.nvim

Repository files navigation

ember.nvim

Animated ASCII heat-map widgets for Neovim, built with floating windows and highlight groups instead of terminal escape rendering.

ember.nvim is the original editor-integrated version of the project. If you want the standalone terminal application instead, see the sibling ember.term repo.

ember.nvim preview

Features

  • Standalone Neovim plugin with setup, start, stop, toggle, set_intensity, stats, and benchmark
  • Three scenes: fire, lava, spiral
  • Non-focusable floating window that survives buffer switching
  • Palette system with auto, gruvbox, default, or custom highlight specs
  • Optional nvim-tree attach mode with automatic fallback to float mode
  • Commands: :EmberStart, :EmberStop, :EmberToggle, :EmberBenchmark

Installation

Release Status

ember.nvim is shipping as a v1.0.0 source/plugin release. Install it through your plugin manager or from the repository directly; there are no compiled binary assets for this repo.

lazy.nvim

{
  "yourname/ember.nvim",
  config = function()
    require("ember").setup({
      width = 33,
      height = 12,
      fps = 8,
      scene = "fire",
      palette = "auto",
      heat_levels = 11,
      full_rewrite_threshold = 0.6,
      char_ramp = { " ", ".", ":", "^", "*", "x", "#", "%", "@", "&" },
      adaptive_fps = {
        enabled = false,
        idle_fps = 4,
        active_fps = 8,
      },
      wave = {
        enabled = true,
        style = "sway_breathe",
        amount = "subtle",
      },
      attach = {
        mode = "nvim-tree",
      },
    })
  end,
}

packer.nvim

use({
  "yourname/ember.nvim",
  config = function()
    require("ember").setup()
  end,
})

Usage

require("ember").setup()
require("ember").start()
require("ember").start({ scene = "lava" })
require("ember").start({ scene = "spiral" })
require("ember").stop()
require("ember").toggle()
require("ember").set_intensity(0.4)
require("ember").stats()
require("ember").benchmark({ frames = 180 })

The public API is intentionally small so other plugins, statusline setups, or personal automation can script it easily:

require("ember").start({ width = 33, height = 12, fps = 8 })
require("ember").stop()
require("ember").set_intensity(0.4)
require("ember").stats()
require("ember").benchmark({ frames = 180 })

Scene Notes

Lava currently looks a little odd, but it is interesting enough to keep around as a distinct scene.

Lava Preview

Lava preview

Spiral Preview

Spiral preview

Lava Example

require("ember").setup({
  scene = "lava",
  lava = {
    blobs = 4,
    speed = 0.16,
    pulse_amount = 0.08,
  },
})

Spiral Example

require("ember").setup({
  scene = "spiral",
  width = 33,
  height = 12,
  spiral = {
    turns = 1.9,
    thickness = 1.2,
    rotation_speed = 0.24,
    pulse_amount = 0.08,
  },
})

Commands

  • :EmberStart
  • :EmberStop
  • :EmberToggle
  • :EmberBenchmark [frames]

Configuration

require("ember").setup({
  width = 33,
  height = 12,
  fps = 8,
  adaptive_fps = {
    enabled = false,
    idle_fps = 4,
    active_fps = 8,
  },
  full_rewrite_threshold = 0.6,
  scene = "fire", -- "fire" | "spiral" | "lava"
  zindex = 40,
  border = "none",
  row_offset = 1,
  col_offset = 0,
  intensity = 0.65,
  palette = "auto", -- "auto" | "gruvbox" | "default" | custom table
  heat_levels = 11,
  char_ramp = { " ", ".", ":", "^", "*", "x", "#", "%", "@", "&" },
  wave = {
    enabled = true,
    style = "sway_breathe",
    amount = "subtle",
  },
  lava = {
    blobs = 4,
    speed = 0.16,
    pulse_amount = 0.08,
    center_bias_x = 0,
    center_bias_y = 0,
  },
  spiral = {
    turns = 1.85,
    thickness = 1.15,
    rotation_speed = 0.24,
    pulse_amount = 0.08,
    center_bias_x = 0,
    center_bias_y = 0,
  },
  force_palette = false,
  attach = {
    mode = "nvim-tree", -- "float" | "editor" | "nvim-tree"
    position = "bottom-left",
  },
})

wave.amount supports subtle, medium, and pronounced for the fire scene. The default subtle profile uses a slow sway and breathing cycle for ambient motion rather than dramatic oscillation.

The spiral table applies only to scene = "spiral" and controls the vortex turns, width, rotation speed, pulse, and center offset.

The lava table applies only to scene = "lava" and controls how many soft blobs drift through the widget, how quickly they move, how much they pulse, and how the whole scene is biased within the window. Lava uses the same warm ember palette and char ramp as the rest of the plugin.

adaptive_fps is optional and drops to idle_fps when ember is visually quiet, then returns to active_fps as motion picks back up. full_rewrite_threshold controls when the renderer stops doing dirty-row updates and rewrites the entire frame instead.

require("ember").stats() returns cumulative runtime counters for frames, dirty rows, rewritten rows, nvim_buf_set_lines calls, highlight calls, and timing breakdowns for render, line updates, namespace clears, and highlight work. require("ember").benchmark() runs an offscreen benchmark using the current config shape and returns the same timing categories as per-frame averages.

Custom palettes use the same shape passed to nvim_set_hl:

require("ember").setup({
  custom_palette = {
    { fg = "#282828" },
    { fg = "#3c3836" },
    { fg = "#504945" },
    { fg = "#665c54" },
    { fg = "#7c6f64" },
    { fg = "#8f3f1f" },
    { fg = "#af3a03" },
    { fg = "#cc241d" },
    { fg = "#d65d0e" },
    { fg = "#fe8019" },
    { fg = "#fabd2f" },
    { fg = "#fbf1c7" },
  },
})

Users and themes can also define EmberFire0 through EmberFire11 directly if they want full control over the rendered colors.

Performance Notes

  • Replaced per-cell highlight updates with contiguous highlight runs.
  • Switched frame updates to dirty-row writes with a full-frame fallback threshold.
  • Added reusable renderer buffers and row-aware frame materialization to cut steady-state allocations.
  • Added runtime profiling with stats() and benchmark breakdowns for render, line updates, namespace clears, and highlights.
  • Tuned the spiral scene to reduce expensive math and dramatically reduce full rewrites on larger canvases.

In the current benchmark pass, spiral 80x24 improved from roughly 0.48ms to 0.26ms average frame time while also dropping from frequent full rewrites to only occasional ones.

Changelog

See CHANGELOG.md for the current optimization summary and release notes.

Health Check

Run :checkhealth ember to confirm Neovim version support and optional nvim-tree integration availability.

About

Animated ASCII campfire for Neovim.

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages