docs/getting-started/QUICKSTART.md

# Raxol Quickstart

Get started with Raxol in 5, 10, or 15 minutes. Choose your path based on what you need.

## What is Raxol?

Raxol is a terminal UI framework for Elixir that scales from simple buffers to full applications:

- **Raxol.Core** - Lightweight buffer primitives (< 100KB, zero deps)
- **Raxol.LiveView** - Render terminals in Phoenix LiveView
- **Raxol** (full) - Complete framework with plugins and enterprise features

Start small, add features as needed.

---

## 5-Minute Tutorial: Your First Buffer

Just want to draw boxes and text? Use Raxol.Core.

### Installation

```elixir
# mix.exs
def deps do
  [
    {:raxol, "~> 2.0"}  # Or {:raxol_core, "~> 2.0"} for minimal install
  ]
end
```

```bash
mix deps.get
```

### Hello Buffer

Create a file `hello.exs`:

```elixir
alias Raxol.Core.{Buffer, Box}

# Create a 40x10 buffer
buffer = Buffer.create_blank_buffer(40, 10)

# Draw a double-line box
buffer = Box.draw_box(buffer, 0, 0, 40, 10, :double)

# Write some text
buffer = Buffer.write_at(buffer, 5, 4, "Hello, Raxol!")

# Render it
IO.puts(Buffer.to_string(buffer))
```

Run it:

```bash
elixir hello.exs
```

Output:
```
╔══════════════════════════════════════╗
║                                      ║
║                                      ║
║                                      ║
║     Hello, Raxol!                    ║
║                                      ║
║                                      ║
║                                      ║
║                                      ║
╚══════════════════════════════════════╝
```

**That's it!** Pure functional, no servers, no complexity.

### Key Concepts (5 min version)

1. **Create** - `Buffer.create_blank_buffer(width, height)`
2. **Draw** - `Box.draw_box()`, `Box.fill_area()`, etc.
3. **Write** - `Buffer.write_at(buffer, x, y, text)`
4. **Render** - `Buffer.to_string(buffer)` for output

Buffers are just data structures. No magic.

---

## 10-Minute Tutorial: LiveView Integration

Want to show a terminal in your Phoenix app? Add LiveView integration.

### Add Dependency

```elixir
# mix.exs
def deps do
  [
    {:raxol_core, "~> 2.0"},
    {:raxol_liveview, "~> 2.0"},
    {:phoenix_live_view, "~> 0.20 or ~> 1.0"}
  ]
end
```

### Create a LiveView

```elixir
# lib/my_app_web/live/terminal_live.ex
defmodule MyAppWeb.TerminalLive do
  use MyAppWeb, :live_view
  alias Raxol.Core.{Buffer, Box}

  def mount(_params, _session, socket) do
    # Create initial buffer
    buffer = Buffer.create_blank_buffer(80, 24)
    buffer = Box.draw_box(buffer, 0, 0, 80, 24, :rounded)
    buffer = Buffer.write_at(buffer, 10, 10, "Hello from LiveView!", %{})

    # Schedule periodic updates (optional)
    if connected?(socket), do: Process.send_after(self(), :tick, 1000)

    {:ok, assign(socket, buffer: buffer, count: 0)}
  end

  def render(assigns) do
    ~H"""
    <div>
      <h1>Live Terminal</h1>
      <.live_component
        module={Raxol.LiveView.TerminalComponent}
        id="terminal"
        buffer={@buffer}
        theme={:nord}
        on_keypress={&handle_keypress/1}
        on_click={&handle_click/1}
      />
    </div>
    """
  end

  def handle_info(:tick, socket) do
    # Update buffer every second
    count = socket.assigns.count + 1
    buffer = Buffer.write_at(
      socket.assigns.buffer,
      10, 12,
      "Ticks: #{count}",
      %{fg_color: :cyan}
    )

    Process.send_after(self(), :tick, 1000)
    {:noreply, assign(socket, buffer: buffer, count: count)}
  end

  def handle_keypress(key) do
    IO.puts("Key pressed: #{key}")
  end

  def handle_click({x, y}) do
    IO.puts("Clicked at: #{x}, #{y}")
  end
end
```

### Add Route

```elixir
# lib/my_app_web/router.ex
scope "/", MyAppWeb do
  pipe_through :browser

  live "/terminal", TerminalLive
end
```

### Include CSS

```elixir
# lib/my_app_web/components/layouts/root.html.heex
<link rel="stylesheet" href={~p"/assets/raxol_terminal.css"} />
```

### Start Server

```bash
mix phx.server
# Visit http://localhost:4000/terminal
```

**You now have a live terminal in your web app!** Updates in real-time, handles keyboard/mouse events.

### Available Themes

Choose from built-in themes:
- `:nord` - Nord color scheme
- `:dracula` - Dracula theme
- `:solarized_dark` - Solarized Dark
- `:solarized_light` - Solarized Light
- `:monokai` - Monokai

---

## 15-Minute Tutorial: Interactive Terminal

Build a fully interactive REPL-style terminal.

### The Plan

We'll create:
1. Command input at the bottom
2. Scrollable output area
3. Command history (up/down arrows)
4. Real-time updates

### Full Implementation

```elixir
defmodule MyAppWeb.InteractiveTerminalLive do
  use MyAppWeb, :live_view
  alias Raxol.Core.{Buffer, Box, Renderer}

  @width 80
  @height 24
  @output_height 22
  @input_height 2

  def mount(_params, _session, socket) do
    socket =
      socket
      |> assign(
        buffer: create_initial_buffer(),
        output_lines: ["Welcome to Interactive Terminal!", "Type 'help' for commands"],
        input: "",
        history: [],
        history_index: 0
      )
      |> update_display()

    {:ok, socket}
  end

  def render(assigns) do
    ~H"""
    <div class="interactive-terminal">
      <.live_component
        module={Raxol.LiveView.TerminalComponent}
        id="terminal"
        buffer={@buffer}
        theme={:nord}
        on_keypress={fn key -> send(self(), {:key, key}) end}
      />
    </div>
    """
  end

  def handle_info({:key, key}, socket) do
    socket =
      case key do
        "Enter" ->
          socket
          |> execute_command()
          |> clear_input()

        "Backspace" ->
          update(socket, :input, fn input ->
            String.slice(input, 0..-2//1)
          end)

        "ArrowUp" ->
          navigate_history(socket, :up)

        "ArrowDown" ->
          navigate_history(socket, :down)

        char when byte_size(char) == 1 ->
          update(socket, :input, fn input -> input <> char end)

        _ ->
          socket
      end
      |> update_display()

    {:noreply, socket}
  end

  defp create_initial_buffer do
    Buffer.create_blank_buffer(@width, @height)
    |> Box.draw_box(0, 0, @width, @height, :double)
    |> Box.draw_horizontal_line(0, @output_height, @width, "=")
  end

  defp update_display(socket) do
    buffer = create_initial_buffer()

    # Render output lines (last N lines that fit)
    output_lines = Enum.take(socket.assigns.output_lines, -(@output_height - 2))
    buffer =
      output_lines
      |> Enum.with_index()
      |> Enum.reduce(buffer, fn {line, idx}, buf ->
        Buffer.write_at(buf, 2, idx + 1, line, %{})
      end)

    # Render input line
    buffer =
      Buffer.write_at(
        buffer,
        2, @output_height + 1,
        "> #{socket.assigns.input}",
        %{fg_color: :cyan}
      )

    assign(socket, buffer: buffer)
  end

  defp execute_command(socket) do
    input = String.trim(socket.assigns.input)

    if input != "" do
      output = process_command(input)

      socket
      |> update(:output_lines, fn lines ->
        lines ++ ["> #{input}"] ++ output
      end)
      |> update(:history, fn hist -> [input | hist] end)
      |> assign(history_index: 0)
    else
      socket
    end
  end

  defp process_command("help") do
    [
      "Available commands:",
      "  help      - Show this help",
      "  clear     - Clear output",
      "  echo TEXT - Echo back text",
      "  time      - Show current time",
      "  exit      - Close terminal"
    ]
  end

  defp process_command("clear") do
    # Clear handled separately
    []
  end

  defp process_command("echo " <> text) do
    [text]
  end

  defp process_command("time") do
    [DateTime.utc_now() |> to_string()]
  end

  defp process_command("exit") do
    ["Goodbye!"]
  end

  defp process_command(cmd) do
    ["Unknown command: #{cmd}. Type 'help' for available commands."]
  end

  defp clear_input(socket) do
    assign(socket, input: "")
  end

  defp navigate_history(socket, direction) do
    history = socket.assigns.history
    index = socket.assigns.history_index

    new_index =
      case direction do
        :up -> min(index + 1, length(history))
        :down -> max(index - 1, 0)
      end

    input =
      if new_index > 0 and new_index <= length(history) do
        Enum.at(history, new_index - 1)
      else
        ""
      end

    socket
    |> assign(input: input)
    |> assign(history_index: new_index)
  end
end
```

### What You've Built

- **Command input** - Type commands at the bottom
- **Command history** - Up/Down arrows navigate history
- **Scrollable output** - Shows last 20 lines
- **Real-time rendering** - Instant visual updates
- **Themed UI** - Professional Nord theme

### Try It

```bash
mix phx.server
# Visit http://localhost:4000/terminal
# Type: help
# Type: echo Hello World
# Type: time
# Press up arrow to recall commands
```

---

## What's Next?

### Add More Features

**Syntax highlighting:**
```elixir
# Use Style module
style = Raxol.Core.Style.new(fg_color: :green, bold: true)
buffer = Buffer.write_at(buffer, x, y, "def function", style)
```

**Progress bars:**
```elixir
# Draw a progress bar
progress = 0.75  # 75%
width = 40
filled = round(width * progress)

buffer = Box.fill_area(buffer, 2, 10, filled, 1, "█", %{fg_color: :green})
buffer = Box.fill_area(buffer, 2 + filled, 10, width - filled, 1, "░", %{fg_color: :gray})
```

**Multiple panels:**
```elixir
# Split screen layout
buffer = Box.draw_box(buffer, 0, 0, 40, 24, :single)      # Left panel
buffer = Box.draw_box(buffer, 40, 0, 40, 24, :single)     # Right panel
```

### Explore More

- **[Core Concepts](./CORE_CONCEPTS.md)** - Deep dive into buffers and rendering
- **[Migration Guide](./MIGRATION_FROM_DIY.md)** - Already have a terminal renderer?
- **[Cookbook](../cookbook/README.md)** - Practical patterns and recipes
- **[API Reference](../core/BUFFER_API.md)** - Complete function documentation

### Examples Directory

Check out working examples:
```bash
# Run examples
mix run examples/core/01_hello_buffer.exs
mix run examples/core/02_box_drawing.exs
mix run examples/liveview/01_simple_terminal/
```

### Performance Targets

Raxol.Core is built for speed:
- **Buffer operations**: < 1ms for 80x24 grids
- **Rendering**: < 16ms (60fps capable)
- **Memory**: < 100KB per buffer
- **Dependencies**: Zero runtime dependencies

### Get Help

- **GitHub Issues**: https://github.com/Hydepwns/raxol/issues
- **Documentation**: Browse `docs/` directory
- **Examples**: Working code in `examples/`

---

## Frequently Asked Questions

### Do I need the full Raxol framework?

No! Start with `raxol_core` for just buffers, add `raxol_liveview` for web integration, or use `raxol` for everything.

### Can I use this with my existing Phoenix app?

Yes! Raxol.LiveView integrates seamlessly with Phoenix LiveView.

### Does this work in production?

Yes. Raxol is production-ready with 99%+ test coverage and performance benchmarks.

### Can I customize the themes?

Yes! Either use built-in themes or create custom CSS. See [Theming Cookbook](../cookbook/THEMING.md).

### What about mobile browsers?

Yes! The LiveView component is responsive and works on mobile (though keyboard input is limited to mobile keyboards).

---

## Quick Reference

### Buffer Operations

```elixir
# Create
buffer = Buffer.create_blank_buffer(80, 24)

# Write
buffer = Buffer.write_at(buffer, x, y, "text", style)

# Read
cell = Buffer.get_cell(buffer, x, y)

# Clear
buffer = Buffer.clear(buffer)

# Resize
buffer = Buffer.resize(buffer, new_width, new_height)

# Render
output = Buffer.to_string(buffer)
diff = Renderer.render_diff(old_buffer, new_buffer)
```

### Box Drawing

```elixir
# Styles: :single, :double, :rounded, :heavy, :dashed
buffer = Box.draw_box(buffer, x, y, width, height, :double)

# Lines
buffer = Box.draw_horizontal_line(buffer, x, y, length, "-")
buffer = Box.draw_vertical_line(buffer, x, y, length, "|")

# Fill
buffer = Box.fill_area(buffer, x, y, width, height, " ", style)
```

### Styles

```elixir
# Create style
style = Style.new(
  fg_color: :cyan,
  bg_color: :black,
  bold: true,
  italic: false,
  underline: false
)

# Merge styles
new_style = Style.merge(base_style, %{bold: true})

# Colors: :black, :red, :green, :yellow, :blue, :magenta, :cyan, :white
# Or RGB: {255, 128, 0}
# Or 256-color: 42
```

---

**Ready to build?** Pick a tutorial above and start coding!