Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improved interactive development #157

Open
Kevinpgalligan opened this issue Jan 28, 2024 · 12 comments
Open

Improved interactive development #157

Kevinpgalligan opened this issue Jan 28, 2024 · 12 comments

Comments

@Kevinpgalligan
Copy link
Contributor

Kevinpgalligan commented Jan 28, 2024

Things to add:

  • (Gleefre's suggestion) Have a slot/option like :restart-on-redefinition nil, so the window doesn't have to restart every time the defsketch is recompiled. If someone is just tweaking the drawing code, for example, or how the state gets updated (as opposed to adding new state), then they may not need to restart the window. Or even if they're adding new state, maybe they don't need to refresh (this might require ensuring that the new draw doesn't get called before any new slots are added).
  • May also want another config option to control whether the slots are reinitialised with prepare.
  • A hook or hotkey (like close-on) to manually trigger restarts.

Together, these features would enable something closer to "true" interactive development.

@aykaramba
Copy link

I would love to see this feature because Sketch is really annoying in my tiling window manager ... on every recompile the window is restarted and my window manager renders the window in a slightly different place (which is correct for my workflow).

Anyone know what it would take to implement this feature?

@Kevinpgalligan
Copy link
Contributor Author

I've never been sure exactly how the window gets reinitialized. I imagine it's something to do with update-instance-for-redefined-class - maybe sdl2kit provides an implementation of that method that recreates the window? I'll look into it when I get the chance.

@aykaramba
Copy link

I am learning Lisp and don't know enough to dig in to that level my self yet. I will try to help if I can.

@Kevinpgalligan
Copy link
Contributor Author

I've done some experimenting with the current version of Sketch. The window isn't getting recreated for me when I recompile a defsketch, and it stays in the same position. I suspect that this was fixed when we removed kit.sdl2:gl-window as a superclass of the sketch class.

We do, however, reset all the slots to their default values, and we trigger the setup method to be called again.

I'm imagining the user might want to tweak the drawing logic and SOME of the slots, without resetting all of them or invoking setup. E.g. the sketch is a bouncing ball, they want to preserve the current position of the ball when they recompile but update the formula used to compute its new position, some constants (slots) used in the formula, and the appearance of the ball.

Straightforward solution: if restart-on-redefinition is t, then don't call prepare or setup on redefinition. Then all the state is preserved, while the user can tweak the draw logic. But what if they want to tweak some of the slots while preserving others? Either they move such parameters to global variables ( (defparameter *g* 9.81) ), or maybe we allow them to specify slots that should always be redefined.

Maybe....

(defsketch foo
    ((x 0)
     (y 0)
     (g 9.81 :adjustable))
   (do-stuff))

Or...

(defsketch foo
    ((x 0)
     (y 0)
     (g 9.81)
     (pi 3.14)
     (adjustable-slots '(g pi)))
   (do-stuff))

@Kevinpgalligan
Copy link
Contributor Author

Kevinpgalligan commented Nov 4, 2024

Live coding is now possible in Sketch! These ideas were implemented here, although it's completely undocumented: Kevinpgalligan@4032f57

The final API looks like:

(defsketch moon
    ((x 0)
     (y 0)
     (c +white+ :tweakable t)
     (bg +black+ :tweakable t)
     (restart-on-change nil)
     (restart-on :r)
  (background bg)
  (setf x (mod (+ x (random 10) -5) width)
        y (mod (+ y (random 10) -5) height))
  (with-pen (make-pen :fill c)
    (circle x y 15)))
  • In this sketch, you can recompile the defsketch form and it won't restart the window or affect the existing state (x and y) of the Sketch.
  • If you add :tweakable t to one of the slots, that means it WILL be updated when you recompile the defsketch, and thus you can tweak the background colour and the colour of the moon while preserving the position of the moon.
  • Finally, it adds a keyboard shortcut, "r", to manually reset the state of the sketch (again, without closing the window). The default is F1.

Feel free to check out the dev branch of my fork and experiment, feedback appreciated.

@aykaramba
Copy link

Amazing!

@aykaramba
Copy link

I tried loading up your dev branch, I am running into a few problems.

  1. I am using Debian 12.5.

  2. I updated quicklisp repos just in case.

  3. I deleted all instances of sketch just in case.

  4. I git cloned this branch int my local-projects folder from here: https://github.com/Kevinpgalligan/sketch/tree/dev

  5. When I (ql:quickload :sketches) I get an error about floats:

Value of (- 1 -1) in (FLOAT-DIGITS (- 1 -1)) is 2, not a FLOAT.
[Condition of type SIMPLE-TYPE-ERROR]

Restarts:
0: [TRY-RECOMPILING] Recompile noise and try loading it again
1: [RETRY] Retry loading FASL for #<CL-SOURCE-FILE "sketches" "noise">.
2: [ACCEPT] Continue, treating loading FASL for #<CL-SOURCE-FILE "sketches" "noise"> as having been successful.
3: [RETRY] Retry ASDF operation.
4: [CLEAR-CONFIGURATION-AND-RETRY] Retry ASDF operation after resetting the configuration.
5: [ABORT] Give up on "sketches"
6: [REGISTER-LOCAL-PROJECTS] Register local projects and try again.
7: [RETRY] Retry SLY mREPL evaluation request.
8: [*ABORT] Return to SLY's top level.
9: [ABORT] abort thread (#<THREAD "sly-channel-1-mrepl-remote-1" RUNNING {1001398003}>)

Backtrace:
0: (SB-C::%COMPILE-TIME-TYPE-ERROR (2) FLOAT # ((- 1 -1)) "(FLOAT-DIGITS (- 1 -1))" NIL)
Locals:
ATYPE = FLOAT
CAST-CONTEXT = NIL
CODE-CONTEXT = "(FLOAT-DIGITS (- 1 -1))"
DETAIL = ((- 1 -1))
VALUES = (2)
1: ((SB-C::TOP-LEVEL-FORM (FLOAT-DIGITS (- 1 -1)))) [toplevel]
[No Locals]
2: (SB-FASL::LOAD-FASL-GROUP #S(SB-FASL::FASL-INPUT :STREAM #<SB-SYS:FD-STREAM for "file /home/user/.cache/common-lisp/sbcl-2.2.9.debian-linux-x64/home/user/mnt/work/desktop/user/common-lisp/ske..
3: ((LAMBDA NIL :IN SB-FASL::LOAD-AS-FASL))
Locals:
SB-FASL::FASL-INPUT = #S(SB-FASL::FASL-INPUT ..)
4: (SB-IMPL::CALL-WITH-LOADER-PACKAGE-NAMES #<FUNCTION (LAMBDA NIL :IN SB-FASL::LOAD-AS-FASL) {1009F3C67B}>)
Locals:
FUNCTION = #<FUNCTION (LAMBDA () :IN SB-FASL::LOAD-AS-FASL) {1009F3C67B}>
5: (SB-FASL::LOAD-AS-FASL #<SB-SYS:FD-STREAM for "file /home/user/.cache/common-lisp/sbcl-2.2.9.debian-linux-x64/home/user/mnt/work/desktop/user/common-lisp/sketches/src/noise.fasl" {1009F38CB3}..
6: ((LABELS SB-FASL::LOAD-STREAM-1 :IN LOAD) #<SB-SYS:FD-STREAM for "file /home/user/.cache/common-lisp/sbcl-2.2.9.debian-linux-x64/home/user/mnt/work/desktop/user/common-lisp/sketches/src/noise..
7: (SB-FASL::CALL-WITH-LOAD-BINDINGS #<FUNCTION (LABELS SB-FASL::LOAD-STREAM-1 :IN LOAD) {7F5ED2374C7B}> #<SB-SYS:FD-STREAM for "file /home/user/.cache/common-lisp/sbcl-2.2.9.debian-linux-x64/home/rta..
8: (LOAD #P"/home/user/.cache/common-lisp/sbcl-2.2.9.debian-linux-x64/home/user/mnt/work/desktop/user/common-lisp/sketches/src/noise.fasl" :VERBOSE NIL :PRINT NIL :IF-DOES-NOT-EXIST :ERROR :EXTE..
9: (UIOP/UTILITY:CALL-WITH-MUFFLED-CONDITIONS #<FUNCTION (LAMBDA NIL :IN UIOP/LISP-BUILD:LOAD*) {1009F3869B}> ("Overwriting already existing readtable ~S." #(#:FINALIZERS-OFF-WARNING :ASDF-FINALIZERS)))
10: (ASDF/LISP-ACTION:PERFORM-LISP-LOAD-FASL #<ASDF/LISP-ACTION:LOAD-OP > #<ASDF/LISP-ACTION:CL-SOURCE-FILE "sketches" "noise">)
11: ((SB-PCL::EMF ASDF/ACTION:PERFORM) # # #<ASDF/LISP-ACTION:LOAD-OP > #<ASDF/LISP-ACTION:CL-SOURCE-FILE "sketches" "noise">)
12: ((LAMBDA NIL :IN ASDF/ACTION:CALL-WHILE-VISITING-ACTION))
13: ((:METHOD ASDF/ACTION:PERFORM-WITH-RESTARTS (ASDF/LISP-ACTION:LOAD-OP ASDF/LISP-ACTION:CL-SOURCE-FILE)) #<ASDF/LISP-ACTION:LOAD-OP > #<ASDF/LISP-ACTION:CL-SOURCE-FILE "sketches" "noise">) [fast-method..
14: ((:METHOD ASDF/ACTION:PERFORM-WITH-RESTARTS :AROUND (T T)) #<ASDF/LISP-ACTION:LOAD-OP > #<ASDF/LISP-ACTION:CL-SOURCE-FILE "sketches" "noise">) [fast-method]
15: ((:METHOD ASDF/PLAN:PERFORM-PLAN (T)) #<ASDF/PLAN:SEQUENTIAL-PLAN {1001C4D483}>) [fast-method]
16: ((FLET SB-C::WITH-IT :IN SB-C::%WITH-COMPILATION-UNIT))
17: ((:METHOD ASDF/PLAN:PERFORM-PLAN :AROUND (T)) #<ASDF/PLAN:SEQUENTIAL-PLAN {1001C4D483}>) [fast-method]
18: ((:METHOD ASDF/OPERATE:OPERATE (ASDF/OPERATION:OPERATION ASDF/COMPONENT:COMPONENT)) #<ASDF/LISP-ACTION:LOAD-OP > #<ASDF/SYSTEM:SYSTEM "sketches"> :PLAN-CLASS NIL :PLAN-OPTIONS NIL) [fast-method]
19: ((SB-PCL::EMF ASDF/OPERATE:OPERATE) # # #<ASDF/LISP-ACTION:LOAD-OP > #<ASDF/SYSTEM:SYSTEM "sketches"> :VERBOSE NIL)
--more--

  1. If I accept the error I get other errors around not finding various things in /src ... I guess this issue is first.

Thoughts? I'm pretty sure I am doing something wrong.

@Kevinpgalligan
Copy link
Contributor Author

You should try loading sketch instead, my sketches project only seems to work with my version of SBCL 😄 Or, if you really want to use it, open noise.lisp in the sketches repo and change all the parts saying (random-state:generate-float -1 1) to (random-state:generate-float -1.0 1.0). Or, just wait for me to fix it!

@Kevinpgalligan
Copy link
Contributor Author

Kevinpgalligan commented Nov 4, 2024

Pushed a fix to sketches, feel free to try it out. (Haven't actually tested that it still works).

@aykaramba
Copy link

aykaramba commented Nov 5, 2024

Just dropping in to let you know that it does error out with missing things like rain.fasl (and a few others) but I can just accept, get it running and play around! None of the errors are an issue, don't spend any time on that, just have fun.

Hey thanks, that looks great, appreciate it. I wasn't expecting a quick response, awesome!

@Kevinpgalligan
Copy link
Contributor Author

Hm, weird, I don't think I've gotten an error like that before. Happy to help debug if anything's not working, just create an issue over in the sketches repo. Thanks for checking it out!

@aykaramba
Copy link

Just dropping in to say thank you for the updates and the samples! I played with all of them, really great work! I will use them to do a whole bunch of learning.

Thanks again.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants