off-topic

Stephen Castro-Starkey 2026-01-20T15:56:05.638109Z

Does anybody do any work with https://data-star.dev/ ? I found a project where someone was building a fairly full featured library (https://github.com/nakkaya/weave/) around it and am having a lot of fun. Wondering if anybody else has any experience and would like to chat more.

2026-01-29T12:14:13.934179Z

Cool, thanks for the elevator pitch - were you by any chance the guy who gave an interview about datastar on hx-pod?πŸ˜…

2026-01-29T12:17:25.449279Z

I'd actually love to try it for building a simple html table with some interactivity (as in : you can enter data in specific fields - so a bit like a spreadsheet with stronger rules and more logic in the background). Is there a close-enough example for something like that?

Delaney Gillilan 2026-01-29T14:03:38.659929Z

I'm the author of Datastar, yes. Yes https://data-star.dev/examples/dbmon

Delaney Gillilan 2026-01-29T14:04:47.408419Z

This is Go, but basic idea...

package examples

import (
	"fmt"
	""
	""
	. ""
	""
	"math/rand/v2"
	"net/http"
	"slices"
	"sync"
	"time"
)

type dbmonQuery struct {
	elapsed time.Duration
	query   string
}

type dbmonDatabase struct {
	name    string
	queries []dbmonQuery
}

type dbmonDatabases struct {
	databases []*dbmonDatabase
}

type dbmonInput struct {
	MutationRate int `json:"mutationRate"`
	Fps          int `json:"fps"`
}

type dbmonSettings struct {
	MutationRate int `json:"_mutationRate"`
	Fps          int `json:"_fps"`
}

func setupDBmon(examplesRouter chi.Router) {
	dbs := newDBmonDatabases(6)
	mutationRate := 0.5
	mu := &sync.RWMutex{}
	fps := 144
	avgWindow := 20

	var settings = func() *dbmonSettings {
		return &dbmonSettings{
			MutationRate: int(mutationRate * 100),
			Fps:          fps,
		}
	}

	examplesRouter.Route("/dbmon", func(dbmonRouter chi.Router) {
		dbmonRouter.Get("/", func(w http.ResponseWriter, r *http.Request) {
			u := auth.UserFromContext(r.Context())
			RenderPage(dbmon(u, dbs.databases, 0), w, r)
		})

		dbmonRouter.Put("/inputs", func(w http.ResponseWriter, r *http.Request) {
			input := &dbmonInput{}
			if err := datastar.ReadSignals(r, input); err != nil {
				sse := datastar.NewSSE(w, r)
				sse.ConsoleError(err)
				return
			}

			mu.Lock()
			if input.MutationRate >= 0 && input.MutationRate <= 100 {
				mutationRate = float64(input.MutationRate) / 100
			}
			if input.Fps > 0 && input.Fps <= 240 {
				fps = input.Fps
			}
			mu.Unlock()

			w.WriteHeader(204)
		})

		dbmonRouter.Get("/updates", func(w http.ResponseWriter, r *http.Request) {
			d := time.Second / time.Duration(fps)
			t := time.NewTicker(d)
			defer t.Stop()

			// Add 10 second timeout
			timeout := time.NewTimer(10 * time.Second)
			defer timeout.Stop()

			avg := 1
			renderTime := 0 * time.Second

			sse := datastar.NewSSE(w, r, datastar.WithCompression())
			for {
				select {
				case <-r.Context().Done():
					return
				case <-timeout.C:
					// Timeout reached, show "Are you still there?" message
					sse.PatchElementTempl(dbmonTimeout())
					return
				case <-t.C:
					t.Reset(time.Second / time.Duration(fps))

					mu.Lock()
					dbs.randomUpdate(mutationRate)
					mu.Unlock()

					avg = (avg*(avgWindow-1) + int(renderTime)) / avgWindow

					sse.MarshalAndPatchSignals(settings())

					now := time.Now()
					sse.PatchElementTempl(dbmonApp(dbs.databases, time.Duration(avg)))
					renderTime = time.Since(now)

				}
			}
		})
	})
}

func randomQuery() dbmonQuery {
	elapsed := time.Duration(rand.Float64()*15) * time.Millisecond
	query := `SELECT blah from something`

	if rand.Float32() < 0.2 {
		query = `<IDLE> in transaction`
	}

	if rand.Float32() < 0.1 {
		query = `vacuum`
	}

	return dbmonQuery{
		elapsed: elapsed,
		query:   query,
	}
}

func newDBmonDatabase(format string, args ...any) *dbmonDatabase {
	db := &dbmonDatabase{
		name: fmt.Sprintf(format, args...),
	}
	db.update()
	return db
}

func (db *dbmonDatabase) update() {
	r := rand.N(10) + 6
	db.queries = make([]dbmonQuery, r)

	for i := range r {
		db.queries[i] = randomQuery()
	}

	slices.SortFunc(db.queries, func(a, b dbmonQuery) int {
		return int(a.elapsed - b.elapsed)
	})
}

func newDBmonDatabases(n int) *dbmonDatabases {
	dbs := &dbmonDatabases{
		databases: make([]*dbmonDatabase, n*2),
	}

	for i := 0; i < n*2; i += 2 {
		dbs.databases[i] = newDBmonDatabase("cluster%d", i/2+1)
		dbs.databases[i+1] = newDBmonDatabase("cluster%dslave", i/2+1)
	}

	return dbs
}

func (dbs *dbmonDatabases) randomUpdate(r float64) {
	for _, db := range dbs.databases {
		if rand.Float64() < r {
			db.update()
		}
	}
}

templ dbmon(u *auth.User, dbs []*dbmonDatabase, renderTime time.Duration) {
	@page(u, "dbmon") {
		@Demo() {
			@dbmonApp(dbs, renderTime)
		}
		@Heading("HTML")
		@HtmlCodeHighlight(`
            <div
                id="demo"
                data-init="@get('/examples/dbmon/updates')"
                data-signals:_editing__ifmissing="false"
            >
                <p>
                    Average render time for entire page: { renderTime }
                </p>
                <div role="group">
                    <label>
                        Mutation Rate %
                        <input
                            type="number"
                            min="0"
                            max="100"
                            value="20"
                            data-on:focus="$_editing = true"
                            data-on:blur="@put('/examples/dbmon/inputs'); $_editing = false"
                            data-attr:data-bind:mutation-rate="$_editing"
                            data-attr:data-bind:_mutation-rate="!$_editing"
                        />
                    </label>
                    <label>
                        FPS
                        <input
                            type="number"
                            min="1"
                            max="144"
                            value="60"
                            data-on:focus="$_editing = true"
                            data-on:blur="@put('/examples/dbmon/inputs'); $_editing = false"
                            data-attr:data-bind:fps="$_editing"
                            data-attr:data-bind:_fps="!$_editing"
                        />
                    </label>
                </div>
                <table style="table-layout: fixed; width: 100%; word-break: break-all">
                    <tbody>
                        <!-- Dynamic rows generated by server -->
                        <tr>
                            <td>cluster1</td>
                            <td style="background-color: var(--_active-color)" class="success">
                                8
                            </td>
                            <td aria-description="SELECT blah from something">
                                12ms
                            </td>
                            <!-- More query cells... -->
                        </tr>
                        <!-- More database rows... -->
                    </tbody>
                </table>
            </div>
        `)
		@Heading("Explanation")
		<p>
			Per a conversation on the discord server there was a desire to port an old React Conf
			talk, <a href="">DBMon</a>, to Datastar.
		</p>
		<p>
			The logic is 1:1 but all done on the backend, and since it's Go, it's an interesting
			comparison to the SPA based approach. We've limited purely since the site is run on a
			free tier server and don't want to be a bad user. If you run the site from source you
			can easily 10x the rows without major issues.
		</p>
		@Subheading("Note")
		<p>
			If you open your Network tab in DevTools we are leveraging ZSTD compression so the data
			rate is relatively low for the contents.
		</p>
	}
}

templ dbmonApp(dbs []*dbmonDatabase, renderTime time.Duration) {
	<div
		id="demo"
		data-init="@get('/examples/dbmon/updates')"
		data-signals:_editing__ifmissing="false"
	>
		<p>
			Average render time for entire page: { renderTime }
		</p>
		<div role="group">
			<label>
				Mutation Rate %
				<input
					type="number"
					min="0"
					max="100"
					value="20"
					data-on:focus="$_editing = true"
					data-on:blur="@put('/examples/dbmon/inputs'); $_editing = false"
					data-attr:data-bind:mutation-rate="$_editing"
					data-attr:data-bind:_mutation-rate="!$_editing"
				/>
			</label>
			<label>
				FPS
				<input
					type="number"
					min="1"
					max="144"
					value="60"
					data-on:focus="$_editing = true"
					data-on:blur="@put('/examples/dbmon/inputs'); $_editing = false"
					data-attr:data-bind:fps="$_editing"
					data-attr:data-bind:_fps="!$_editing"
				/>
			</label>
		</div>
		<table style="table-layout: fixed; width: 100%; word-break: break-all">
			<tbody>
				for _, db := range dbs {
					{{
	count := len(db.queries)
					}}
					<tr>
						<td>{ db.name }</td>
						<td
							style="background-color: var(--_active-color)"
							if count >= 15 {
								class="error"
							} else {
								if count >= 10 {
									class="warning"
								} else {
									class="success"
								}
							}
						>
							{ count }
						</td>
						for _, q := range db.queries[:5] {
							<td aria-description={ q.query }>
								{ q.elapsed }
							</td>
						}
					</tr>
				}
			</tbody>
		</table>
	</div>
}

templ dbmonTimeout() {
	<div id="demo" class="text-center">
		<h2>Are you still there?</h2>
		<p>Updates have been paused to save bandwidth and reduce COβ‚‚ emissions.</p>
		<p class="text-sm text-gray-600">We don't want to waste resources if you've stepped away!</p>
		<button
			class="btn btn-primary"
			data-on:click="window.location.reload()"
		>
			Refresh to resume
		</button>
	</div>
}

2026-01-29T14:15:48.308079Z

Sweet, thanks!

2026-01-29T14:16:07.379489Z

Btw I really enjoyed the interview:)

πŸ«‚ 1
Delaney Gillilan 2026-01-29T15:15:58.043899Z

thanks. D* makes it really easy just send down a new copy of your table when you want... that's it

Delaney Gillilan 2026-01-29T15:16:21.739999Z

D* is an FRP engine for the web done right imo

Ben Sless 2026-01-20T16:09:26.204969Z

@andersmurphy

☝️ 1
πŸ™ 1
Asier 2026-01-20T16:11:35.682859Z

We do. We have built one project and we have started a new one in Jan.

πŸ™Œ 2
Marco 2026-01-20T16:23:14.068109Z

@asier.galdos very interesting. how can I go there?

2026-01-20T16:44:13.009989Z

I don't use weave directly, but it's a really nice way to get started with datastar.

❀️ 1
Marco 2026-01-20T17:04:00.631499Z

let me check

Stephen Castro-Starkey 2026-01-20T17:06:44.905099Z

Neat! I'm building a little app using weave and it's pretty nifty. I wonder if we should have a channel for it?

πŸ™Œ 1
Marco 2026-01-20T17:20:50.341809Z

Great!

Marco 2026-01-20T17:21:26.303929Z

do you need some help from me? @stephen676

Marco 2026-01-20T17:23:21.324299Z

I am very interesting to build some app using weave. πŸ˜„

Stephen Castro-Starkey 2026-01-20T17:26:00.382199Z

Well it's a spare time project and likely to become open source so it would have to be for fun. If you want to ensemble with us I can ask the other guy I've been pairing with. He and I meet again this Saturday.

Marco 2026-01-20T17:26:43.068389Z

ok, thanks @stephen676

Stephen Castro-Starkey 2026-01-22T11:45:54.601369Z

One thing I can't find at all is any example of doing authentication using openid connect or even webauthn. Seems like a bit of a pain? I'm sure once I've nailed down the encoding/decoding situation all will be well. But boy do I wish for someone to have solved this already πŸ˜†

Marco 2026-01-22T12:16:16.015499Z

@stephen676. yeah, right. most frameworks don't include OIDC/WebAuthn because they're complex standards.

Marco 2026-01-22T12:18:06.671019Z

I can help you. I think encoding/decoding you mentioned is usually handled by these libraries. passport , passport-openidconnect , express-session am I right?

Marco 2026-01-22T12:19:03.062049Z

authentication is a pain point! Many developers feel the same way. πŸ˜„

Stephen Castro-Starkey 2026-01-22T12:21:27.002229Z

Yeah those work for more traditional JavaScript-based apps. Not so much for server-side rendered. Unless of course we move the boundary to more client-side for the auth piece. Was hoping to avoid JavaScript as much as possible

Marco 2026-01-22T12:24:42.064369Z

hmmm. Which framework do you prefer, then?

Stephen Castro-Starkey 2026-01-22T12:25:40.132309Z

Well I'm working with weave which is based on datastar

Stephen Castro-Starkey 2026-01-22T12:25:47.983709Z

It's super new.

Stephen Castro-Starkey 2026-01-22T12:26:32.255859Z

I have the feeling we are at a wild frontier .. fun and scary 🀣

πŸ™Œ 1
πŸš€ 1
Marco 2026-01-22T12:27:46.096489Z

I am also enjoy like that. πŸ˜„

Marco 2026-01-22T12:28:29.577879Z

shall we work on together?

πŸš€ 1
Delaney Gillilan 2026-01-22T21:05:50.812629Z

I've heard good things about Datastar, careful though... it's a cult

Stephen Castro-Starkey 2026-01-22T21:14:37.204479Z

Yeah the hardest part has been convincing it to do things it wasn't really designed to do. The boundary between server-side and client-side is so fuzzy...

Delaney Gillilan 2026-01-22T21:15:06.295889Z

If you have specifics sure @andersmurphy or i can help

Stephen Castro-Starkey 2026-01-22T21:15:49.641619Z

Sweet.. thanks! What would you think of having a #data-star channel?

Delaney Gillilan 2026-01-22T21:17:26.146079Z

I mean there is already a #data-clojure on the D* discord. but up to y'all

Stephen Castro-Starkey 2026-01-22T21:43:52.903599Z

Oh!

Stephen Castro-Starkey 2026-01-22T21:43:59.609809Z

I go look there πŸ™‚

Delaney Gillilan 2026-01-22T21:44:06.730809Z

πŸš€

Marco 2026-01-23T05:11:35.975429Z

me, too

πŸš€ 1
Marco 2026-01-23T05:17:55.244369Z

@delaneygillilan I can't #data-clojure channel. I am not sure I am in right place on the discord.

Marco 2026-01-23T05:18:38.244129Z

let me check.

Marco 2026-01-23T05:19:29.824679Z

can you send me the server name?

Delaney Gillilan 2026-01-23T05:19:51.371939Z

https://discord.gg/9ZesYPNu

πŸ™Œ 1
Marco 2026-01-23T05:21:46.942419Z

Great!!!

2026-01-26T15:25:07.048879Z

From what I understood it's basically htmx but with oob-swap as default behavior. I am really curious whether it can make hypermedia stuff even simpler than htmx but I haven't found the motivation to move out of my htmx comfort zone so far

Delaney Gillilan 2026-01-26T21:35:08.228889Z

It not like that at all... Well it does have some similarity from the outside but very different core

Delaney Gillilan 2026-01-26T21:38:59.233329Z

It's a unified framework, not a library. Most pages need zero JS Fastest signals/reactivity of any JS framework Fastest morph (10-30x faster than idiomorph) You can change any part of any page at any time (works great with CQRS/datalog style dev) SDKs for 14+ languages including streaming 40-300x compression in most SDKs Plugin system built like a game engine, the core is < 500 loc and everything else (even SSE) is a plugin 11kb, which is smaller than HTMX or Alpine or hyperscript... but does more than all 3 Spec compliant HTML for everything Has been proven out to go VERY well with CLJ ideals, playes perfectly with hiccup and is an immediate mode engine for left fold of state Built by a game engine programmer that hates JS but loves Lisp (even if he doesn't use it) Modular so you can take out any part or do your own thing Actively dogfooded (HTMX website is a SPA for example) on production apps. More actively developed than HTMX

Delaney Gillilan 2026-01-26T21:40:35.974489Z

They look the same until you try both or measure πŸ˜›

Delaney Gillilan 2026-01-26T21:42:45.202919Z

If you have specific questions @aaronrebmann i'm happy to answer. Clojure is my favorite language I don't actively use

Melody 2026-01-20T20:52:56.941309Z

https://m.youtube.com/watch?v=Ozipf13jRr4 I've enjoyed β€œThinking Allowed” in the past and I totally forgot that the host of this show got the opportunity to interview John McCarthy. Pretty cool to get to listen to our lisp grandpa talk about ai and stuff. I watched this hoping he would go over KIF but I think this may have been even earlier than 1992.

πŸ‘€ 4
βž• 1
πŸ™ 1
john 2026-01-30T05:15:12.755549Z

The one I saw most recently was on synchronicity

john 2026-01-30T05:15:46.128119Z

Mishlove is great

Melody 2026-01-27T15:06:37.670139Z

Me too! I think the first episode I saw was with Terrance McKenna but there have been many amazing guests and the interviews are always very enlightening. Do you have a favorite episode?

john 2026-01-27T03:57:55.178459Z

Love that show