You are browsing as a guest. Sign up (or log in) to start making projects!

ethmarks

@ethmarks

Joined June 13th, 2026

  • 60Devlogs
  • 4Projects
  • 5Ships
  • 62Votes
Ahoy! I'm Ethan Marks. I'm 15 years old and I'm in my third year of dual-enrollment. I love programming, especially web development.

https://github.com/ethmarks
Ship

No Let: a JS puzzle site where you aren’t allowed to use let or anything with mutable state.

This second ship was about implementing the fantastic suggestions in the feedback I got from my first ship.

  • I added anti-hardcoding checks to stop people from cheesing the puzzles
  • I added two new levels, including a very difficult one
  • I added confetti and visual feedback when a user completes a puzzle
  • I added a favicon
  • …Plus a handful of small tweaks and improvements

I’m looking forward to reading the feedback I get this time :)

  • 7 devlogs
  • 10h
Try project → See source code →
Open comments for this post

40m 56s logged

Final devlog before ship #2 :roo-so-excited:

  • I added difficulty ratings for each puzzle
  • I moved the logic/linter output (aka the checklist) right above the “run” button because it makes more sense there
  • I updated the README and added some screenshots
0
0
27
Open comments for this post

2h 9m 16s logged

How the heck did this take 2 hours…

All that I did in this devlog was improve the Conway’s Game of Life puzzle a bit. I rewrote some of the starter and solution code for simplicity (I can’t believe I forgot about the .flatMap() method), and I also wrote a bunch of comments that explain the starter code and solution code.

Next, I think I’ll add a difficulty indicator for the puzzles. I think I’ll probably be ready to re-ship after that!

0
0
111
Open comments for this post

4h 11m 16s logged

Hi! It’s been a while. Again.

The highlight of this devlog is the new puzzle: Conway’s Game of Life. In the feedback on my first ship, several people mentioned that they wanted more challenging levels. Well, here ya go! This puzzle is much more complex, and it also doesn’t lend itself well to functional programming, so you have to get creative in order to make the linter happy. Personally, after I designed the puzzle and wrote the starter code, it took me over 45 minutes to write the solution code. It’s pretty difficult, so hopefully it’ll satisfy the users who want a challenge.


I also made a few smaller changes:

  • I removed dev.css’s light mode, because all the rest of my styling is meant for dark mode
  • I set Maple Mono as the preferred font, but I intentionally made it only work if you already have Maple Mono installed, because I know that not everybody likes it
  • I added a special message if you try to run empty code

Next, I think I’ll start adding comments to some of the starter code and solution code. I think it’d be helpful for users who aren’t as familiar with JavaScript or function programming, so that they can more easily get acquainted with the starter code, and so that they can learn how the solution works if they choose to use it.

0
0
20
Open comments for this post

1h 5m 55s logged

I made a new puzzle! The puzzle involves implementing a Caesar cipher. That’s it, actually. It’s certainly not a very difficult puzzle, but it does contribute to puzzle variety.

Also, do you notice the new favicon? No more Svelte logo!

0
0
41
Open comments for this post

29m 23s logged

…i think the user would have more feedback/satisfaction if upon completion, something else happens to let them know they successfully completed a puzzle, something like confetti, or even just the “run” button changing color/text

When the puzzle states changes to “passed” (meaning the logic test and linter both passed) from some other status, I made it trigger a confetti effect via canvas-confetti and made the run button turn green.

Next, I’m probably going to make a favicon.

0
0
38
Open comments for this post

27m 31s logged

One thing: I can just cheese everything by changing the output manually. I recommend you use multiple test cases so i can not just type “return 6” and complete the task.

I added secretInput values to the rest of the puzzles to fix the hardcoding cheese. I also mentioned the anti-hardcoding in the README.

Next, I’m going to work on adding some confetti and whatnot for when the user’s code passes both the logic test and the linter.

0
0
45
Open comments for this post

46m 57s logged

Hi again! It’s been a while. I’m coming back to No Let because when I shipped it the first time, the lovely people who rated it took the time to write really thoughtful feedback and suggest great actionable improvements. So i thought it’d be fun to implement your suggestions (and also I was bored).

Here are some excerpts from the feedback I got:

One thing: I can just cheese everything by changing the output manually. I recommend you use multiple test cases so i can not just type “return 6” and complete the task.

Anyway, my biggest critique would be the lack of levels. I think that adding tiers of difficulty, along with 10-15 more levels would take this project to the highest possible level.

…svelte favicon ;)…

…i think the user would have more feedback/satisfaction if upon completion, something else happens to let them know they successfully completed a puzzle, something like confetti, or even just the “run” button changing color/text

I intend to fix/implement each one of these. With the exception of the “10-15 levels” one; that’s a bit more than I’m willing to make, but I will add some new puzzles.


So far, I’ve started implementing the first suggestion. I’m creating secretInput values for each puzzle, and in the test function, after it evaluates the input (which is publicly displayed), it runs the code again using the secretInput.

If the code passes the input check but fails the secretInput check, it fails the logic test with this message:

Failed secret anti-hardcoding check. You need to generalize your logic.

I’ve only added secretInputs for two puzzles so far, so the work is still ongoing.

0
0
19
Ship

Deci: a terminal text editor based on nano

It’s a fully-functional text editor that can be used to create and edit all types of text files. It has unique behavior for 112 keybinds, cursor movement modeled on Zed and VS Code, integrated Markdown previewing, and an undo/redo buffer.

  • 17 devlogs
  • 37h
  • 18.81x multiplier
  • 704 Stardust
Try project → See source code →
Open comments for this post

2h 7m 34s logged

v1.0.0 release! Yay!

I added the following stuff:

  • a new screenshot gallery to the site
  • --version and --help commands to the CLI
  • small tweaks to the readme
  • text in the center of the header that says what file is open

I’ll write the next devlog using deci.

0
0
17
Open comments for this post

3h 42m 14s logged

I finished the README, did some bugfixes and refactors, and made a demo gif using VHS.


Unless I think of more features to add, this will probably be my second-to-last devlog. I’m still planning on writing my final devlog before shipping using deci.

1
0
22
Open comments for this post

2h 58m 16s logged

I wrote a first draft of the README. I’m pretty happy with it so far. I still need to add a “How it Works” section, though.

Oh and I also expanded the help screen to add more info.

0
0
18
Open comments for this post

2h 7m 26s logged

I added undo and redo!


Basically, every mutative keystroke (e.g. space or backspace) makes a snapshot of the current lines and editor position and adds it to the history slice. When you press ctrl+z, it decrements historyIndex and replaces the current lines and cursor position with history[historyIndex]. ctrl+y does the same thing but the opposite.


Oh and I also added word-skipping cursor movement. If you press ctrl+left or ctrl+right, the cursor will move in that direction until it reaches a delimiter (e.g. a space or a punctuation). It took embarrassingly long to get it to work perfectly. There’s a bunch of little edge case behaviors for cursor caret movement that are really subtle and kinda unintuitive, but which you’re so used to from writing text on computers that you can instantly spot if it’s not quite correct.


I think that next I’ll start working on the README.

0
0
29
Open comments for this post

2h 2m 27s logged

I added markdown previewing!

Just press ctrl+p, and it’ll switch to a new screen and render the current editor content as markdown with Glamour. The screenshot for this devlog is what the current README looks like when previewed.

It obviously works best with markdown files, but I’ve been unable to make it throw an error, even when I try to render .go files and whatnot that are definitely not markdown. I guess markdown is a pretty permissive spec.

I also added goreleaser, so it should automatically build binaries and release them for each new version now. You can check it out at https://github.com/ethmarks/deci/releases.


I think that deci is pretty close to finished. I honestly can’t think of much more to add. I still need to add that undo buffer that I promised in the first devlog, and write a README and better docs, but that’s basically it. How exciting!

0
0
33
Open comments for this post

3h 33m 31s logged

I refactored the rendering code so that it doesn’t break styled content.


I realized earlier today that there was absolutely zero reason for me to use a grid data structure in the rendering logic. The rendering pipeline went something like this:

  1. input a bunch of lines
  2. create a blank 2D grid of characters, one for each character in the terminal
  3. iterate over every single cell in that grid and set it to the relevant character from the input lines
  4. join all the columns in each row of the grid together into one line each
  5. join all lines together into one big string
  6. output the string for rendering

Using an extra intermediate dimension of data storage didn’t actually do anything except use way more memory and make it very difficult to use non-ASCII characters.

So I redesigned it and the new rendering pipeline works more like this:

  1. input a bunch of lines
  2. create a slice of blank lines, one for each row in the terminal
  3. trim the relevant input line and insert it into the slice
  4. join all the lines together into one big string
  5. output the string for rendering

This way is much simpler, and also much more memory efficient i think.


Plus, the new pipleine lets me used styled text. Before, when I tried out Lipgloss’s Border feature on the help page, the border was composed entirely of â characters. Idk why. I think it because each grid cell only used the first byte and didn’t consider the invisible ANSI characters. But the new one slices it safely using Charm’s ansi package, so it’s safe to use styled lines.

I used the new pipeline to make the help page more colorful and aesthetic. I made each character of the “deci” ASCII art be a different color to distinguish them, because a friend pointed out that the c and the i are really close together so it kinda looks like it says “ded”.

Soon, I should be able to add markdown previewing. It shouldn’t even be that much work (famous last words).

0
0
20
Open comments for this post

25m 29s logged

Just a small change this devlog. I added a keybind to change the cursor shape. The default is now block (it was bar before, but that seemed kinda un-nano), and you can toggle it to bar and then underline using alt+c.

I also added optional anonymous condition functions to the keybind struct, so I can toggle whether a keybind is visible or not. For example, the “Write Out” keybind is only visible on the editor screen because there’s no reason to write out the help screen.

0
0
19
Open comments for this post

3h 27m 59s logged

I’ve added a help screen and a keybind info bar!


For the help screen, I had to majorly refactor how line data is stored. Previously, there was just one big lines slice that was instantiated from the file content, directly written to to process keystrokes, and directly read from to render the view. But now I’ve moved most of that functionality to a separate editorLines variable, and lines is now a pointer that can be hotswapped. So when the user switches to the help screen, I just change the lines pointer from editorLines to helpLines, and voila everything works. As a bonus, this modular system should make it pretty easy to add markdown previews later.

I made the ASCII art “deci” logo in the help page using the Colossal font for FIGlet, which is the same font that nano uses for the ASCII art on its home page. I think it looks pretty good.

I’m also leaning into the slogan “your second-to-last next editor”. It’s a self-deprecating play on Zed’s slogan that I made up for the first devlog. But I’m really proud of it so I put it on the website and in the help screen.


The keybind info bar was pretty simple to make. The only thing worth remarking on is that it automatically limits the displayed keybinds to the width of the terminal screen, just like nano. Speaking of which, did you know that nano has 66 keybinds? I counted. I had to stretch a terminal window across two 1080p monitors and scale the font size down to 58% in order to see all of them. Currently, deci has 3 keybinds. I’ll need to think of more keybinds, because that’s embarrassing. Maybe a toggle between block mode and bar mode for the cursor.

0
0
15
Ship

Hadronize: a quark-themed set collection game.

It has a web UI with a custom SvelteKit virtual layout engine, a polyglot CLI that runs across Node, Deno, Bun, and the browser console, a QuickJS bot sandbox, a comprehensive test suite, and more.

I’m really proud of Hadronize and hope that you enjoy it.

  • 26 devlogs
  • 118h
  • 19.09x multiplier
  • 2150 Stardust
Try project → See source code →
Open comments for this post

26m 14s logged

Shipping

I did a few miscellaneous things like make the remote script endpoint production-ready, fix some typos across the project, and create a favicon in Inkscape.

After I write this devlog, I’m going to press the big “Ship your project!” button. If you’re a reviewer reading this: I hope you enjoy Hadronize. It’s one of my biggest projects ever, and I’m really proud of how it’s turned out.

1
0
38
Loading more…

Followers

Loading…