hyperfiddle

grounded_sage 2025-06-02T14:16:03.845519Z

Is this the canonical source for electric changes? -> https://github.com/hyperfiddle/electric A new snapshot is made available when main changes? Experiencing more frequent than expected downloads of snapshots. Accompanied by slower than expected download speed. Asking to aid with isolating what the issue I am experiencing is.

Dustin Getz (Hyperfiddle) 2025-06-02T14:38:48.013219Z

you can find the date of last snapshot here: https://clojars.org/com.hyperfiddle/electric/versions/v3-alpha-SNAPSHOT

Dustin Getz (Hyperfiddle) 2025-06-02T14:39:38.783209Z

no, github is not guaranteed to match the snapshot publication

Dustin Getz (Hyperfiddle) 2025-06-02T14:40:21.881579Z

also, we have started maintaining a https://docs.google.com/document/d/17BE7xpV9bFoPq9scLJHCF8hD5gBm00K0Up45N3XeG5c/edit?tab=t.0#heading=h.ojrtp4t0j7h7 (instead of just a slack announcement)

🙏 4
⚡ 2
oλv 2025-06-02T15:04:06.637919Z

Hello friends! 👋 A few weeks back, me and @daslu put together an experimental library for rendering https://scicloj.github.io/kindly-noted/kindly visualizations in Electric: https://github.com/itonomi/kindly-electric It is super useful already, thanks to the breadth of visualizations offered by https://github.com/scicloj/kindly-render! We've used it at https://itonomi.com/ for some neat real-time visualizations of our RAG jobs and it worked great right out of the box! 🤓 Please try it out and ping me about any bugs or feedback otherwise!

🔥 9
oλv 2025-06-02T15:05:40.453719Z

And here's a quick one-liner to run the playground locally 😄

git clone  /tmp/kindly-electric && cd /tmp/kindly-electric/playground && clojure -A:dev -X dev/-main

Daniel Slutsky 2025-06-02T15:13:59.365749Z

Fantastic

😄 1
Daniel Slutsky 2025-06-02T15:21:50.243069Z

Looks great. I just shared your message at the #kindly-dev channel at Zulip. https://clojurians.zulipchat.com/#narrow/channel/454856-kindly-dev/topic/electric/near/521773989 electric @ 💬>

🙌 1
Melody 2025-06-02T17:10:19.773189Z

Can someone help me understand what I am doing wrong in this cide? It is kind of a lot of code but I don't know how else to ask this question. @dustingetz To save space here I will put the code on a reply to this comment

Dustin Getz (Hyperfiddle) 2025-06-03T11:48:59.259959Z

(e/defn match-brain-activity-server []
  (e/server
   (match-brain-activity-impl)))
e/defn names must be capitalized, not sure if this is connected with your error somehow

Dustin Getz (Hyperfiddle) 2025-06-03T11:49:40.136659Z

i dont think the code in the repo matches the bug report

Dustin Getz (Hyperfiddle) 2025-06-03T11:51:33.120719Z

I suspect a hot code reloading issue actually

Dustin Getz (Hyperfiddle) 2025-06-03T11:53:35.784259Z

the Electric hot code reloader will auto reload all dirty cljc namespaces and also reload the corresponding jvm clojure macro namespace, but it will not auto reload .clj files for example, which can get tricky especially as you refactor code

👀 1
Melody 2025-06-02T17:10:52.024419Z

I follow this pattern to try and match live data streaming from a device:

(e/defn StartStreamingWhenMatching []
  (e/client
   (let [state (e/watch pong-state/state)
         connected? (get-in state [:bci :device-connected?])
         matching? (get-in state [:bci :matching?])
         streaming? (get-in state [:bci :streaming?])]
     ;; Start streaming when we start matching (if not already streaming)
     (when (and connected? matching? (not streaming?))
       (js/console.log "Starting EEG streaming for brain activity matching")
       (let [stream-result (e/server (bci/start-eeg-streaming-server "pong"))]
         (js/console.log "Stream start result:" (clj->js stream-result))
         (when (:success stream-result)
           (swap! pong-state/state assoc-in [:bci :streaming?] true)))))))

(e/defn PollBrainActivityWhenMatching []
  (e/client
   (let [state (e/watch pong-state/state)
         connected? (get-in state [:bci :device-connected?])
         matching? (get-in state [:bci :matching?])
         streaming? (get-in state [:bci :streaming?])]
     ; Poll when connected, matching, and streaming
     (when (and connected? matching? streaming?)
       ; Should execute whenever the state changes
       (let [confidence-data (e/server (bci/match-brain-activity-server))]
         (js/console.log "Brain activity confidence:" (clj->js confidence-data))
         (when confidence-data
           (swap! pong-state/state assoc-in [:bci :confidence] confidence-data)))))))

and then I am trying to extend the same 'BrainControls'


(e/defn BrainControls []
  (e/client
   (let [state (e/watch pong-state/state)
         connected? (get-in state [:bci :device-connected?])
         pending-connect? (get-in state [:bci :pending-connect])
         pending-disconnect? (get-in state [:bci :pending-disconnect])
         active-profile (get-in state [:bci :active-profile])
         connection-error (get-in state [:bci :connection-error])
         matching? (get-in state [:bci :matching?])
         streaming? (get-in state [:bci :streaming?])
         confidence (get-in state [:bci :confidence])]

     (ConnectWhenPending)
     (DisconnectWhenPending)
     (StartStreamingWhenMatching)
     (StopStreamingWhenNotMatching)
     (PollBrainActivityWhenMatching)

...the rest of the code is the same...
      ; Brain matching toggle (only show when connected)
      (when connected?
        (dom/button
         (dom/props {:class (str "bci-button " (if matching? "stop-matching" "start-matching"))})
         (dom/text (if matching? "Stop Brain Control" "Start Brain Control"))
         (dom/On "click"
                 (fn [_]
                   (swap! pong-state/state assoc-in [:bci :matching?] (not matching?)))
                 nil)))

      ; Show active profile info
      (when (and connected? active-profile)
        (dom/div
         (dom/props {:class "profile-info"})
         (dom/text (str "Profile: " active-profile))
         (when streaming?
           (dom/span
            (dom/props {:class "streaming-indicator"})
            (dom/text " • Streaming")))))

      ; Show brain activity confidence when matching
      (when (and connected? matching? confidence)
        (dom/div
         (dom/props {:class "confidence-display"})
         (dom/div (dom/text (str "Up: " (get confidence :up 0.0))))
         (dom/div (dom/text (str "Down: " (get confidence :down 0.0))))
         (when-let [error (get confidence :error)]
           (dom/div
            (dom/props {:class "confidence-error"})
            (dom/text (str "Error: " error))))))
....)
I keep running into this error and I don't know how to resolve it:
Caused by: clojure.lang.ExceptionInfo:
brain-pong.components/PollBrainActivityWhenMatching:145:40
I cannot resolve [bci/match-brain-activity-server] {:in PollBrainActivityWhenMatching, :for :server}
Why it can't resolve my function? match-brain-activity-server is a big block of only clojure code:
#?(:clj
   (defn match-brain-activity-server
     []
     (try
       (let [recording? @state/recording?
             eeg-data @state/eeg-data]

         (println "Recording? value:" recording? "type:" (type recording?))
         (println "EEG data value:" (if eeg-data "exists" "nil") "type:" (type eeg-data))
....rest of that function
The following code works for me to connect to the device I am working with:
(e/defn ConnectWhenPending []
  (e/client
   (let [state (e/watch pong-state/state)]
     (when (get-in state [:bci :pending-connect])
       (js/console.log "Initiating BCI connection!")
       ; Clear the pending state first
       (swap! pong-state/state assoc-in [:bci :pending-connect] false)

       (let [result (e/server (bci/connect-device))]
         (js/console.log "Connection result:" (clj->js result))
         (if (:connected result)
           (do
             (swap! pong-state/state update-in [:bci] merge
                    {:device-connected? (:connected result)
                     :active-profile (:profile-name result)
                     :connection-error nil})
             (js/console.log "Connection successful"))
           (do
             (swap! pong-state/state update-in [:bci] merge
                    {:device-connected? false
                     :active-profile nil
                     :connection-error (:error result)})
             (js/console.log "Connection failed:" (:error result)))))))))

which calls a bunch of server logic in my bci namespace:

#?(:clj
   (defn connect-device []
     (try
       (initialize-modules!)
       (mount/start)
       (println "Server: Connecting to BCI device with active profile")
       (let [active-profile ((:get-active-profile @state/state))
             active-profile-name (:name active-profile)
             connected? (api/connect-from-profile! active-profile)]
         (println "Connection result:" connected?)
         {:connected connected?
          :profile-name active-profile-name})
       (catch Exception e
         (println "Error in connect-device-server:" (.getMessage e))
         {:connected false :error (.getMessage e)}))))
I put that and a similar disconnect function into this BCIControlComponent and I just call this in my main function and it works
(e/defn BrainControls []
  (e/client
   (let [state (e/watch pong-state/state)
         connected? (get-in state [:bci :device-connected?])
         pending-connect? (get-in state [:bci :pending-connect])
         pending-disconnect? (get-in state [:bci :pending-disconnect])
         active-profile (get-in state [:bci :active-profile])
         connection-error (get-in state [:bci :connection-error])]

     (ConnectWhenPending)
     (DisconnectWhenPending)

     (dom/div
      (dom/props {:class "bci-controls"})

      ; Connection button
      (dom/button
       (dom/props {:class (str "bci-button " (if connected? "disconnect" "connect"))
                   :disabled (or pending-connect? pending-disconnect?)})
       (dom/text (cond
                   pending-connect? "Connecting..."
                   pending-disconnect? "Disconnecting..."
                   connected? "Disconnect Device"
                   :else "Connect Device"))
       (dom/On "click"
               (fn [_]
                 (if connected?
                   (swap! pong-state/state assoc-in [:bci :pending-disconnect] true)
                   (swap! pong-state/state assoc-in [:bci :pending-connect] true)))
               nil))

      ; Show active profile info
      (when (and connected? active-profile)
        (dom/div
         (dom/props {:class "profile-info"})
         (dom/text (str "Profile: " active-profile))))

      ; Show connection error if any
      (when connection-error
        (dom/div
         (dom/props {:class "connection-error"})
         (dom/text (str "Error: " connection-error))))))))

Dustin Getz (Hyperfiddle) 2025-06-02T20:46:16.705079Z

can you give us a link to the actual file so i can like, c-f it

Dustin Getz (Hyperfiddle) 2025-06-02T20:46:23.447409Z

and see the ns form

Dustin Getz (Hyperfiddle) 2025-06-02T20:46:54.314259Z

thank you for collapsing the inline code snippets out of the OP

Melody 2025-06-02T21:22:33.228639Z

@dustingetz @post972 Okay I pushed what I am recently working with but it doesn't work right now because of the issues I shared above. In theory it should work if the StartStreamingWhenMatching, StopStreamingWhenMatching, and PollBrainActivityWhenMatching components are commented out. If you want to run it, it does require that you set up BrainFlow; but hopefully I have streamlined that process as much as possible - First it is necessary to run clj -m setup in the root of brainfloj, and that should both download all the necessary BrainFlow files as well as add it to the deps.edn in the root directory. Secondly, to run the Pong game, which also requires BrainFlow (separately since it is meant to be an 'example application'), Pong itself needs to get setup, and I created a "setup_brainflow.clj" file in the root of the examples namespace. Either running clj -m setup_brainflow or evaluating (-main) in examples/Pong/src/setup_brainflow.clj will add the paths to the Brainflow libs that got downloaded in step one to the Pong game. then the game can start with clj -A:dev -X dev/-main in the examples/Pong directory; but like I am sort of asking about; it doesn't run with the current code I am trying to get to work. If those 3 components are commented out, then the pong game should be working fine and it should open up in the browser at localhost:8080. If it would be preferred for debugging purposes, I can push another version right away that just has it commented out and working in a basic way. https://github.com/TheFakeLorLyons/brainfloj

Melody 2025-06-02T21:31:08.626339Z

^I just went ahead and commented out everything that doesn't work so now the page loads as long as all the dependencies are set up.

Melody 2025-06-02T22:41:45.777889Z

Oh and the match-brain-activity-server function that is giving me problems is in the middle of bci_integration.cljc, the components are in components.cljc and the entry point to everything is main.cljc. The only other namespaces that are relevant are game_state.cljc and signature.clj. I am not using the other files in the game yet.