home.html
html
<!DOCTYPE html>
<html lang="en" data-theme="dark">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>SkyShot - Screenshot as a Service</title>
  <!-- HTMX -->
  <script src="https://cdn.jsdelivr.net/npm/htmx.org@2.0.8/dist/htmx.min.js"
    integrity="sha384-/TgkGk7p307TH7EXJDuUlgG3Ce1UVolAOFopFekQkkXihi5u/6OCvVKyz1W+idaz"
    crossorigin="anonymous"></script>
  <!-- Hyperscript -->
  <script src="https://unpkg.com/hyperscript.org@0.9.12"></script>
  <!-- Tailwind CSS & Daisy UI -->
  <link href="https://cdn.jsdelivr.net/npm/daisyui@5" rel="stylesheet" type="text/css" />
  <link href="https://cdn.jsdelivr.net/npm/daisyui@5/themes.css" rel="stylesheet" type="text/css" />
  <script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
</head>
<body class="min-h-screen bg-base-200 text-base-content">
  {{$screenshots := screenshots}}
  {{$app := req.URL.Query.Get "app"}}
  <!-- Hero Section with Background Screenshot -->
  <div class="hero min-h-[80vh] md:min-h-[60vh] border-b-2 border-white/40"
    style="background-image: url('/{{if $app}}{{$app}}{{else}}apps{{end}}');">
    <div class="hero-overlay bg-opacity-80"></div>
    <div class="hero-content justify-end w-full max-w-7xl">
      <div class="card bg-base-100 shadow-2xl w-full max-w-md" data-theme="light">
        <div class="card-body space-y-4">
          <div class="mb-4">
            <h2 class="card-title text-2xl">
              Screenshot your App
            </h2>
            <p class="text-sm opacity-60 mt-1">Enter any Skyscape app name to capture a screenshot</p>
          </div>
          <input type="text" name="app" id="app-input" placeholder="Enter app name (e.g. skykit)"
            class="input input-bordered w-full" value="{{$app}}" hx-get="/" hx-trigger="input changed delay:500ms"
            hx-push-url="true" hx-target="body" hx-swap="outerHTML" autofocus>
          <form hx-post="/capture">
            <input type="hidden" name="app" value="{{$app}}">
            <button type="submit" class="btn btn-primary btn-block" {{if not $app}}disabled{{end}}>
              <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24"
                stroke="currentColor">
                <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
                  d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
              </svg>
              Recapture Screenshot
            </button>
          </form>
        </div>
      </div>
    </div>
  </div>
  <div class="mx-auto max-w-6xl px-4 py-10 space-y-8">
    <!-- Key Features -->
    <section class="grid md:grid-cols-3 gap-6">
      <div class="card bg-base-100 shadow-md">
        <div class="card-body">
          <h3 class="card-title">
            <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
              <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z" />
            </svg>
            Instant Response
          </h3>
          <p class="text-base-content/70">
            Never wait for screenshots. First request returns immediately with default image while capture runs in
            background. Refresh to see the real screenshot.
          </p>
          <div class="badge badge-outline badge-success mt-2">Always fast</div>
        </div>
      </div>
      <div class="card bg-base-100 shadow-md">
        <div class="card-body">
          <h3 class="card-title">
            <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
              <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
                d="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" />
            </svg>
            Above the Fold
          </h3>
          <p class="text-base-content/70">
            Captures the viewport at 768x432 resolution. Perfect for social cards, link previews, and showcasing your
            app's first impression.
          </p>
          <div class="badge badge-outline badge-info mt-2">Optimized preview</div>
        </div>
      </div>
      <div class="card bg-base-100 shadow-md">
        <div class="card-body">
          <h3 class="card-title">
            <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
              <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
                d="M8 9l3 3-3 3m5 0h3M5 20h14a2 2 0 002-2V6a2 2 0 00-2-2H5a2 2 0 00-2 2v14a2 2 0 002 2z" />
            </svg>
            Simple as HTML
          </h3>
          <p class="text-base-content/70">
            Just use an image tag. No API keys, no SDKs, no configuration. Screenshot any Skyscape app with one line of
            HTML.
          </p>
          <div class="mockup-code text-xs mt-2">
            <pre><code>&lt;img src="https://apps.skysca.pe/skykit" /&gt;</code></pre>
          </div>
        </div>
      </div>
    </section>
    <!-- Recent Screenshots -->
    <section class="space-y-3">
      <div class="flex items-center justify-between">
        <h2 class="text-2xl font-semibold">Recently captured</h2>
        <span class="text-sm text-base-content/70">Latest screenshots</span>
      </div>
      {{$recent := $screenshots.RecentScreenshots}}
      {{if $recent}}
      <div class="grid gap-4 md:grid-cols-3">
        {{range $recent}}
        <a href="/?app={{ .ID }}" class="card bg-base-100 shadow-md hover:shadow-xl transition-shadow">
          <figure class="px-4 pt-4">
            <img src="/{{ .ID }}" alt="Screenshot of {{ .ID }}"
              class="rounded-lg border border-base-300 w-full h-48 object-cover">
          </figure>
          <div class="card-body">
            <p class="text-xs break-all text-base-content/70 font-mono">{{ .ID }}</p>
            <div class="text-xs text-base-content/60">{{ .CreatedAt.Format "Jan 2, 15:04" }}</div>
          </div>
        </a>
        {{end}}
      </div>
      {{else}}
      <div class="p-8 text-center text-base-content/70 border border-dashed border-base-300 rounded-xl">
        No screenshots captured yet. Try entering an app name above!
      </div>
      {{end}}
    </section>
    <!-- Footer -->
    <footer class="text-center text-sm text-base-content/50 pt-8 border-t border-base-300">
      <p>
        Built with <a href="https://theskyscape.com/repo/skykit" class="link">Skykit</a> •
        Part of <a href="https://theskyscape.com" class="link">The Skyscape</a> •
        Made by <a href="https://theskyscape.com/user/ccutch" class="link">@ccutch</a>
      </p>
    </footer>
  </div>
</body>
</html>
bfb9971

updating claude file

Connor McCutcheon
@connor
0 stars

This is an instance of the Strudel app running on The Skyscape

Sign in to comment Sign In
ok can we study chromedp and use skykit to make an app like SkyLinks (maybe called SkyShot) to take pictures of the apps we are running on the network, and that we are reverse proxying with the web-server. I want to build this and launch it as a microservice itself that the web-server will later use once we have finished this exercise. It should have a simple homepage like Lorum Picsum to inform users about the usage and then all other routes will be parsed as URL, we will then take a screenshot and store it as []byte into a model that we can display to the users. If an error occures paring the url, taking the screenshot, or if we take longer than 400ms lets serve a default image, we can use the @web-server/views/public/background.png as a default for now
Connor McCutcheon
@connor
1 month ago