summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEwy <ewy@ewy.one>2026-09-18 15:06:59 +0200
committerEwy <ewy@ewy.one>2026-09-18 15:06:59 +0200
commit1f8364b145dbd0ff9ff7583f50aeb7498967b0f9 (patch)
treecf09f5b2151f1d37327831c00148f8431b527e70
parentb82e6069c9dc93eff6e539a8cccd73e69ecde38e (diff)
add more stuff
-rw-r--r--client/client.go1
-rw-r--r--clients/client.go8
-rw-r--r--engine/game.go2
-rw-r--r--go.mod19
-rw-r--r--go.sum41
-rwxr-xr-xsakurabin0 -> 13945411 bytes
-rw-r--r--server/server.go21
-rw-r--r--server/web/game/game.js39
-rw-r--r--server/web/game/index.html40
-rw-r--r--server/web/game/style.css3
-rw-r--r--server/web/home.js18
-rw-r--r--server/web/index.gohtml26
-rw-r--r--server/web/index.html19
-rw-r--r--server/web/style.css16
14 files changed, 212 insertions, 41 deletions
diff --git a/client/client.go b/client/client.go
deleted file mode 100644
index da13c8e..0000000
--- a/client/client.go
+++ /dev/null
@@ -1 +0,0 @@
-package client
diff --git a/clients/client.go b/clients/client.go
new file mode 100644
index 0000000..c9b75b0
--- /dev/null
+++ b/clients/client.go
@@ -0,0 +1,8 @@
+package client
+
+import "sakura/engine"
+
+type ClientState struct {
+ Now *engine.Game
+ Preview *engine.Game
+}
diff --git a/engine/game.go b/engine/game.go
index 19880f0..5130864 100644
--- a/engine/game.go
+++ b/engine/game.go
@@ -24,7 +24,7 @@ func (g *Game) propagate() {
func NewGame() *Game {
g := &Game{
Shadow: pool.New(0, pool.Infinite),
- Distance: pool.New(0, 10),
+ Distance: pool.New(10, 10),
Actions: nil,
}
g.Yin = NewPlayer(g)
diff --git a/go.mod b/go.mod
index 65f1164..d8d6a02 100644
--- a/go.mod
+++ b/go.mod
@@ -3,11 +3,30 @@ module sakura
go 1.27
require (
+ github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
+ github.com/charmbracelet/bubbletea v1.3.10 // indirect
+ github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc // indirect
+ github.com/charmbracelet/lipgloss v1.1.0 // indirect
+ github.com/charmbracelet/x/ansi v0.10.1 // indirect
+ github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd // indirect
+ github.com/charmbracelet/x/term v0.2.1 // indirect
+ github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect
github.com/gorilla/websocket v1.5.3 // indirect
+ github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
+ github.com/mattn/go-isatty v0.0.20 // indirect
+ github.com/mattn/go-localereader v0.0.1 // indirect
+ github.com/mattn/go-runewidth v0.0.16 // indirect
+ github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
+ github.com/muesli/cancelreader v0.2.2 // indirect
+ github.com/muesli/termenv v0.16.0 // indirect
github.com/r3labs/diff/v3 v3.0.2 // indirect
+ github.com/rivo/uniseg v0.4.7 // indirect
github.com/spf13/pflag v1.0.10 // indirect
github.com/stretchr/testify v1.12.1 // indirect
github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
+ github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
go.yaml.in/yaml/v3 v3.0.5 // indirect
+ golang.org/x/sys v0.36.0 // indirect
+ golang.org/x/text v0.3.8 // indirect
)
diff --git a/go.sum b/go.sum
index ac2ae0b..95216c6 100644
--- a/go.sum
+++ b/go.sum
@@ -1,7 +1,40 @@
+github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
+github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
+github.com/charmbracelet/bubbletea v1.3.10 h1:otUDHWMMzQSB0Pkc87rm691KZ3SWa4KUlvF9nRvCICw=
+github.com/charmbracelet/bubbletea v1.3.10/go.mod h1:ORQfo0fk8U+po9VaNvnV95UPWA1BitP1E0N6xJPlHr4=
+github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc h1:4pZI35227imm7yK2bGPcfpFEmuY1gc2YSTShr4iJBfs=
+github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc/go.mod h1:X4/0JoqgTIPSFcRA/P6INZzIuyqdFY5rm8tb41s9okk=
+github.com/charmbracelet/lipgloss v1.1.0 h1:vYXsiLHVkK7fp74RkV7b2kq9+zDLoEU4MZoFqR/noCY=
+github.com/charmbracelet/lipgloss v1.1.0/go.mod h1:/6Q8FR2o+kj8rz4Dq0zQc3vYf7X+B0binUUBwA0aL30=
+github.com/charmbracelet/x/ansi v0.10.1 h1:rL3Koar5XvX0pHGfovN03f5cxLbCF2YvLeyz7D2jVDQ=
+github.com/charmbracelet/x/ansi v0.10.1/go.mod h1:3RQDQ6lDnROptfpWuUVIUG64bD2g2BgntdxH0Ya5TeE=
+github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd h1:vy0GVL4jeHEwG5YOXDmi86oYw2yuYUGqz6a8sLwg0X8=
+github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd/go.mod h1:xe0nKWGd3eJgtqZRaN9RjMtK7xUYchjzPr7q6kcvCCs=
+github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ=
+github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg=
+github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4=
+github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM=
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
+github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
+github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
+github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
+github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
+github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4=
+github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88=
+github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
+github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
+github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI=
+github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo=
+github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA=
+github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo=
+github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc=
+github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk=
github.com/r3labs/diff/v3 v3.0.2 h1:yVuxAY1V6MeM4+HNur92xkS39kB/N+cFi2hMkY06BbA=
github.com/r3labs/diff/v3 v3.0.2/go.mod h1:Cy542hv0BAEmhDYWtGxXRQ4kqRsVIcEjG9gChUlTmkw=
+github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
+github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
+github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/testify v1.12.1 h1:EuwCh5fleGS7H32xRwO3wRGT7DxrDhLAT6FF8MpWDWE=
@@ -10,5 +43,13 @@ github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IU
github.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok=
github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g=
github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds=
+github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
+github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
go.yaml.in/yaml/v3 v3.0.5 h1:N6y/pJk8buWs9NY5ERU2HSMfm+IuD/OtfdAnq6kESPw=
go.yaml.in/yaml/v3 v3.0.5/go.mod h1:HVTZu1O7/Vkt2N+BFy8Zza+lnLsABggaTM2ZpNIGuKg=
+golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k=
+golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
+golang.org/x/text v0.3.8 h1:nAL+RVCQ9uMn3vJZbV+MRnydTJFPf8qqY42YiA6MrqY=
+golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
diff --git a/sakura b/sakura
new file mode 100755
index 0000000..def2094
--- /dev/null
+++ b/sakura
Binary files differ
diff --git a/server/server.go b/server/server.go
index 798bab6..af8393d 100644
--- a/server/server.go
+++ b/server/server.go
@@ -3,28 +3,30 @@ package server
import (
"embed"
"fmt"
- "github.com/spf13/pflag"
- "html/template"
+ "io/fs"
"net"
"net/http"
"sakura/cfg"
"sakura/server/api"
"strconv"
+
+ "github.com/spf13/pflag"
)
//go:embed web
var web embed.FS
-var tmpl *template.Template
-
func Start() {
pflag.Parse()
fmt.Println("Server started")
addr := net.JoinHostPort(*cfg.Host, strconv.Itoa(*cfg.Port))
fmt.Printf("Listening on %s\n", addr)
var err error
- tmpl, err = template.ParseFS(web, "web/**.gohtml")
- http.HandleFunc("/{$}", serveHome)
+ if err != nil {
+ panic(err)
+ }
+ sub, err := fs.Sub(web, "web")
+ http.Handle("/", http.FileServer(http.FS(sub)))
http.HandleFunc(cfg.CreateMethod+" "+cfg.CreatePath, api.GameCreate)
http.HandleFunc(cfg.ConnectMethod+" "+cfg.ConnectPath, api.GameConnect)
err = http.ListenAndServe(addr, nil)
@@ -32,10 +34,3 @@ func Start() {
panic(err)
}
}
-
-func serveHome(w http.ResponseWriter, r *http.Request) {
- err := tmpl.ExecuteTemplate(w, "index.gohtml", nil)
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- }
-}
diff --git a/server/web/game/game.js b/server/web/game/game.js
new file mode 100644
index 0000000..5e71786
--- /dev/null
+++ b/server/web/game/game.js
@@ -0,0 +1,39 @@
+"use strict"
+const showGame = (g) => {
+ const tmpl = document.querySelector("template#tmpl")
+ const disp = document.querySelector("#game")
+ const clone = document.importNode(tmpl.content, true)
+ doDistance(clone, g.Distance.Value)
+ disp.replaceChildren(clone)
+};
+
+const doDistance = (clone, value) => {
+ clone.querySelector(".distance").setAttribute("data-value", value);
+ [...clone.querySelectorAll(".distance .sakura")].map((n, i) => {
+ if (i < value) {
+ n.checked = true
+ } else {
+ n.checked = false
+ }
+ })
+
+}
+
+const connect = (gameId) => {
+ const connection = new WebSocket(`/api/game/${gameId}/connect`);
+ window.socket = connection;
+ connection.addEventListener("message", (ev) => {
+ const game = JSON.parse(ev.data);
+ console.debug(game);
+ showGame(game);
+ document.querySelector("#game-json").innerText =
+ JSON.stringify(ev.data, null, 2);
+ });
+}
+
+const init = () => {
+ const id = window.location.hash.slice(1)
+ connect(id)
+}
+
+init()
diff --git a/server/web/game/index.html b/server/web/game/index.html
new file mode 100644
index 0000000..414ff5c
--- /dev/null
+++ b/server/web/game/index.html
@@ -0,0 +1,40 @@
+<!doctype html>
+<html lang="en">
+ <head>
+ <meta charset="UTF-8" />
+ <meta
+ name="viewport"
+ content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"
+ />
+ <meta http-equiv="X-UA-Compatible" content="ie=edge" />
+ <title>sakura | game</title>
+ <link rel="stylesheet" type="text/css" href="/style.css" />
+ <link rel="stylesheet" type="text/css" href="/game/style.css" />
+ </head>
+ <body>
+ <header>
+ <details>
+ <summary>Game state</summary>
+ <pre id="game-json"></pre>
+ </details>
+ </header>
+ <main id="game"></main>
+
+ <template id="tmpl">
+ <div class="distance">
+ <input type="checkbox" class="sakura" />
+ <input type="checkbox" class="sakura" />
+ <input type="checkbox" class="sakura" />
+ <input type="checkbox" class="sakura" />
+ <input type="checkbox" class="sakura" />
+ <input type="checkbox" class="sakura" />
+ <input type="checkbox" class="sakura" />
+ <input type="checkbox" class="sakura" />
+ <input type="checkbox" class="sakura" />
+ <input type="checkbox" class="sakura" />
+ </div>
+ </template>
+
+ <script src="/game/game.js"></script>
+ </body>
+</html>
diff --git a/server/web/game/style.css b/server/web/game/style.css
new file mode 100644
index 0000000..dd0e421
--- /dev/null
+++ b/server/web/game/style.css
@@ -0,0 +1,3 @@
+.hidden {
+ display: none;
+}
diff --git a/server/web/home.js b/server/web/home.js
new file mode 100644
index 0000000..766f246
--- /dev/null
+++ b/server/web/home.js
@@ -0,0 +1,18 @@
+"use strict"
+
+const createGameFromUi = async () => {
+ const g = await newGame()
+ redirect(g)
+}
+
+const newGame = async () => {
+ const game = await fetch("/api/game/create", {
+ method: "POST",
+ });
+ const gameId = await game.text();
+ return gameId
+};
+
+const redirect = (id) => {
+ window.location.assign(`/game/#${id}`)
+}
diff --git a/server/web/index.gohtml b/server/web/index.gohtml
deleted file mode 100644
index d7a90b4..0000000
--- a/server/web/index.gohtml
+++ /dev/null
@@ -1,26 +0,0 @@
-<!doctype html>
-<html lang="en">
-<head>
- <meta charset="UTF-8">
- <meta name="viewport"
- content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
- <meta http-equiv="X-UA-Compatible" content="ie=edge">
- <title>Document</title>
-</head>
-<body>
-
-<script>
- const start = async () => {
- const game = await fetch("/api/game/create", {
- method: "POST",
- })
- const gameId = await game.text()
- const connection = new WebSocket(`/api/game/${gameId}/connect`)
- connection.addEventListener("message", (ev) => {
- console.debug(JSON.parse(ev.data))
- })
- }
- start()
-</script>
-</body>
-</html> \ No newline at end of file
diff --git a/server/web/index.html b/server/web/index.html
new file mode 100644
index 0000000..fda0309
--- /dev/null
+++ b/server/web/index.html
@@ -0,0 +1,19 @@
+<!doctype html>
+<html lang="en">
+ <head>
+ <meta charset="UTF-8" />
+ <meta
+ name="viewport"
+ content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"
+ />
+ <meta http-equiv="X-UA-Compatible" content="ie=edge" />
+ <title>sakura | home</title>
+ <link rel="stylesheet" type="text/css" href="/style.css" />
+ <script src="/home.js"></script>
+ </head>
+ <body>
+ <main>
+ <button type="button" onclick="createGameFromUi()" action="#game-created">Create and join new game</button>
+ </main>
+ </body>
+</html>
diff --git a/server/web/style.css b/server/web/style.css
new file mode 100644
index 0000000..0053142
--- /dev/null
+++ b/server/web/style.css
@@ -0,0 +1,16 @@
+@import "https://ewy.one/terminal.css";
+
+.sakura {
+ min-width: 32px;
+ min-height: 32px;
+ background-color: slategray;
+ pointer-events: none;
+
+ &:not(:disabled) {
+ background-color: lightpink;
+ }
+}
+
+.distance {
+ display: flex;
+}