Shell Wallpaper

In this tutorial, you'll create a wallpaper that runs shell commands and displays their output using a terminal emulator.

Prerequisites

Complete the Getting Started tutorial first.

Declare Shell Commands

Add a shell section to your fluxlay.yaml:

fluxlay.yaml
schemaVersion: 1
name: System Monitor
slug: system-monitor
version: 0.1.0
kind: web
description: A wallpaper that displays live system information.
 
shell:
  macchina:
    run: macchina
    reason: Displays system information in a styled format.
    required:
      - macchina
  fetch-ip:
    run: curl -s https://httpbin.org/ip | jq -r '.origin'
    reason: Retrieves the public IP address.
    required:
      - curl
      - jq
 
network:
  - origin: https://httpbin.org
    reason: Used to fetch the public IP address.

Each command must declare reason (why it's needed) and required (the programs it depends on). Users are prompted to approve commands before they run.

Display Terminal Output

Install Tailwind CSS for styling:

pnpm add -D tailwindcss @tailwindcss/vite

Register the Tailwind plugin in vite.config.ts:

vite.config.ts
import tailwindcss from "@tailwindcss/vite";
import react from "@vitejs/plugin-react";
import { defineConfig } from "vite";
 
import { fluxlay } from "@fluxlay/vite";
 
export default defineConfig({
  plugins: [react(), tailwindcss(), fluxlay()]
});

Update src/main.tsx:

src/main.tsx
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import { useTerminal, useShell, TerminalThemes } from "@fluxlay/react";
import "./index.css";
 
function SystemMonitor() {
  const { terminalRef, instance } = useTerminal({
    fontSize: 13,
    theme: TerminalThemes.tokyoNight
  });
 
  const { error } = useShell("macchina", {
    terminal: instance,
    refreshInterval: 60000
  });
 
  return (
    <main className="h-screen w-screen bg-zinc-900 p-8">
      <div className="h-full w-full rounded-xl overflow-hidden border border-zinc-700">
        {error && <p className="p-4 text-red-400 text-sm">{error}</p>}
        <div ref={terminalRef} className="h-full w-full" />
      </div>
    </main>
  );
}
 
createRoot(document.getElementById("root")!).render(
  <StrictMode>
    <SystemMonitor />
  </StrictMode>
);

Create src/index.css:

src/index.css
@import "tailwindcss";
 
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

Using runShell for Custom Display

For commands where you want to control the display yourself, use runShell:

import { useEffect, useState } from "react";
import { runShell } from "@fluxlay/react";
 
function IpAddress() {
  const [ip, setIp] = useState<string>("...");
 
  useEffect(() => {
    const fetchIp = async () => {
      const result = await runShell("fetch-ip");
      if (result.success) setIp(result.stdout.trim());
    };
    fetchIp();
    const id = setInterval(fetchIp, 30000);
    return () => clearInterval(id);
  }, []);
 
  return <p className="text-zinc-400 text-sm">Public IP: {ip}</p>;
}

Next Steps

Task-focused guides:

When you're ready:

API reference: