A terminal-based color picker application.
Terminal users often need to select colors for themes or UI components. Manually typing hex codes and guessing how they will look is slow and error-prone.
This application solves the problem by providing an interactive interface. It parses hex strings, generates palettes, and displays them visually in the terminal.
Use it to experiment with color combinations and quickly find the right hex codes.
Examples
AppColorPicker.new.run
Source Code
# frozen_string_literal: true # SPDX-FileCopyrightText: 2025 Kerrick Long <me@kerricklong.com> # SPDX-License-Identifier: AGPL-3.0-or-later $LOAD_PATH.unshift File.expand_path("../../lib", __dir__) $LOAD_PATH.unshift File.expand_path(__dir__) require "ratatui_ruby" require_relative "input" require_relative "palette" require_relative "clipboard" require_relative "copy_dialog" require_relative "scene" # A terminal-based color picker application. # # Terminal users often need to select colors for themes or UI components. # Manually typing hex codes and guessing how they will look is slow and error-prone. # # This application solves the problem by providing an interactive interface. It parses hex strings, # generates palettes, and displays them visually in the terminal. # # Use it to experiment with color combinations and quickly find the right hex codes. # # === Examples # # AppColorPicker.new.run # class AppColorPicker # Creates a new <tt>AppColorPicker</tt> instance with a default palette and clipboard. def initialize @input = Input.new @palette = Palette.new(@input.parse) @clipboard = Clipboard.new @dialog = CopyDialog.new(@clipboard) @scene = nil end # Starts the terminal session and enters the main event loop. # # This method initializes the terminal, renders the initial scene, and polls for # input until the user quits. # # === Example # # app = AppColorPicker.new # app.run # def run RatatuiRuby.run do |tui| @scene = Scene.new(tui) loop do render(tui) result = handle_input(tui) break if result == :quit end end end private def render(tui) @clipboard.tick tui.draw do |frame| @scene.render(frame, input: @input, palette: @palette, clipboard: @clipboard, dialog: @dialog) end end private def handle_input(tui) event = tui.poll_event @input.clear_error unless @dialog.active? if @dialog.active? handle_dialog_input(event) else handle_main_input(event) end end private def handle_dialog_input(event) result = @dialog.handle_input(event) case event in { type: :key, code: "q" } | { type: :key, code: "esc" } | { type: :key, code: "c", modifiers: ["ctrl"] } :quit else result end end private def handle_main_input(event) case event in { type: :key, code: "q" } | { type: :key, code: "esc" } | { type: :key, code: "c", modifiers: ["ctrl"] } :quit in { type: :key, code: "enter" } @palette = Palette.new(@input.parse) in { type: :key, code: "backspace" } @input.delete_char in { type: :paste, content: } @input.set(content) @palette = Palette.new(@input.parse) in { type: :key, code: code } @input.append_char(code) in { type: :mouse, kind: "down", button: "left", x:, y: } if @scene && @scene.export_rect&.contains?(x, y) && @palette.main @dialog.open(@palette.main.hex) end else nil end end end AppColorPicker.new.run if __FILE__ == $PROGRAM_NAME