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

b1j2754

@b1j2754

Joined June 19th, 2026

  • 26Devlogs
  • 5Projects
  • 2Ships
  • 30Votes
Katnip -> Compiled Scratch Lang
Polaris -> Lightweight Astronomy App
Open comments for this post

4h 18m 7s logged

Sigma Peak Editor Frfr

The editor is turning out beautifully. Like I love it so far. Tons and tons of improvements to mainly the editor, but a few pivotal improvements to the compiler itself.

Website / GUI Improvements

  • File uploads — no longer are your costumes handwritten svgs :P AND you can import .knip files!
  • QOL improvements — draggable files, auto-focus editor on openning of website
  • Terminal prettification :loveparrot:
  • STAGE BUTTONS! — start / pause / stop + TurboMode
  • Flag functionality rework
    click => compile + run
    shift+click => run without compiling
  • Settings file actually does something

Compiler improvements

  • Costumes implementation (new syntax!)
  • Forever block + more math blocks!
  • Zip compression level compiler flag
0
0
13
Open comments for this post

5h 27m 27s logged

Costumes + Sounds!

Finally, after a long time of putting this off, Katnip finally has syntax to import sounds and assets to use for your projects!

stage {
    costume "./sky.svg";

    events.onFlag() {
        looks.switchBackdrop("sky");
    }
}

sprite Cat {
    costume "./cat.svg" as idle;
    costume "./cat-blink.svg" as blink;
    sound "./meow.wav";

    events.onFlag() {
        motion.goTo(-100, 0);
        looks.switchCostume("idle");
        looks.say("costumes + sounds work", 2);
        forever {
            wait(0.5);
            looks.nextCostume();
        }
    }
}

Changelog

Compiler changes

  • Added costume and sound keywords
  • Added stage keyword for stage override (previously auto-gen’d)
  • Added forever keyword (cuz I forgot to add it somehow)

Website changes

  • Added upload icon for uploading files
  • Added support for the new costume and sound required fs callbacks
  • Added “rename” in dropdown right-click context

Notes

Not sure how the forever block and rename button took this long to add, both seem like something I could’ve adressed earlier, but—better late than never :P

0
0
7
Open comments for this post

4h 12m 1s logged

Fleshing out the GUI

Finally got a working prototype! Check it out at https://katnip.org

Components added:

Stage

This was honestly a pretty hard part of the process. I am using tw-scaffolding, the core vm from TurboWarp. But it has no types, no docs, and the docs that exist are outdated. So I resorted to having Claude make a .d.ts file for me so I could fuzz my way through instead.

This process wasn’t that bad once the functions were clear, and I hooked it up to my compiler—intentionally designed to output Uint8Array.

Toolbar

This was fun since I don’t know svelte yet that well. I had a state originally stored in my state.svelte.ts, but I figure out I could refactor and not need it.

Then I just did some vm tomfoolery to ensure the threads stay open on pausing, and it was good to go.

Terminal

This is a super rudamentry approach. I plan to have an input method at some point, but we will see. Hopefully I implement a better technique, currently I just have a string array storing the logs. Makes it easy to make it stateful in svelte ig

0
0
46
Open comments for this post

4h 26m 47s logged

Katnip GUI!!!

Ahhhh im so excited.
I’m building the gui for Katnip right now—built off a small foundation done by a friend.

Currently repo is private, but I’ll open it once my computer’s not about to die and I’m on stable internet.

Worked on the following things:

  • Re-binding TextMate grammar tokens
  • File editor popup
  • TurboWarp scaffolding library for the running
  • Pulling in my compiler through npm for compilation
0
0
20
Ship

Katnip. For real this time.

From text -> blocks. It now exists.
Fully type-checked. Powerful enums. Function returns.
And it all compiles into scratch.

Over the past 36 hours I have worked on making the IR and Codegen layers come to life. From working with stacks, and other more complex algorithms, hoisting, scopes, and everything in between, It now compiles.

Katnip is a language designed to not just be a surragate for scratch syntax, its supposed to fix it, and offer a scripting alternative. Gone are the days of wrong data types, debugging random lines, Katnip can do that for you. Types and bugs are well defined, and easy to find.

To use this project, I currently do not have a website, but install it through NPM: https://www.npmjs.com/package/@katnip-org/compiler

npm i @katnip-org/compiler

Happy coding :P

  • 6 devlogs
  • 37h
  • 19.83x multiplier
  • 741 Stardust
Try project → See source code →
Open comments for this post

3h 6m 10s logged

Yikes.

So this is a step I didn’t really want to take.
I had to take away a part of the language that I always wanted to exist.

The existence of the temp keyword.

I mean this thing was literally covering my demos and other scripts in the docs and whatnot. But alas, it was not properly implemented, and I have no forseeable good solution to working it out.

So its removed for the time being.

Brighter note

On the flipside, I did finalize and fully implement zip, enumerate, and range!

These functions now properly parse the list arguments and let tuple unpacking do its amazing goodness.

0
0
25
Open comments for this post

4h 41m 49s logged

Cooking up straight peak

Great new features. Genuinely super cool.
This new bout of progress that led to end-to-end compilation has given me so much motivation.

Enums

So, this already existed. But I realized that they are so much more than just a way to create states to check against, or store values in. Ever since I allowed scalar values to be the represenation of enum members, this has become more powerful than I realized.

The key was implementing the type interpretation of an enum. I already was kind of doing this, but when you have an input param for a function, you can assign a type of enum FlowerType for instance. So the input only accepts FlowerType.x where x is the type.

But thats long. Look at a function call:
sniff(FlowerType.DAFFODIL, backup = FlowerType.ROSE);

Instead, I like what typescript does with its discriminant types, allowing a type to represent a set of possible values. So, it was born.

sniff("daffodil", backup = "rose");

In order to use this, just assign values to your enum:

enum FlowerType {
    DAFFODIL = "daffodil",
    ROSE = "rose",
    ...
}

STDLib improvements

Prior, a lot of stuff including type casting was a mess. I just recently got this up and running, so it was hard to even try to think about this.

Scratch only has a few types: round and angled and block. Thats it. And types really only apply to round/angled.

So I implemented small blocks that allow scratch’s oddities and allow you to tell the compiler to “shut up”.

Want to get the string of a bool? No problem.

looks.say( Str(var == 2) + "apple")

And many many other use cases.

Made some marginal improvements to the CLI to allow parsing

Made some commands to run with command pallete for the vscode ext

0
0
15
Open comments for this post

8h 19m 26s logged

Holy Guacamole I’m So Excited

Insane progress over the past few days has occurred, in large part due to my travels on train, and my apparent ability to lock in when I start seeing things.

Codegen

Probably the most recognizable part of the project, Katnip can now generate scratch code. Blocks are being made, and complex patterns written in the IR are finally revealing themselves.

It is so important that you look at the pictures, as the improvements made here are hard to put into words.

Writing this part was arguably the most fun part of the entire project. This part was more scratch-like than any other part so far (“well duh, its the closest stage” you might be saying. And you’d be right.)

IR

Writing a majority did not come without its need for the IR to step up its game. I was quite fed up with 0 visual progress, so I jumped to codegen to boost my morale for the improvements made to the IR.

This includes dict and list slicing, and a proper handling of booleans.

I’m so excited

0
0
77
Open comments for this post

9h 7m 36s logged

The light

I can see it… (what is it?) … the light at the end of the tunnel… (what are you talking about?) .. its almost here

Yea no it ain’t

Though the project isn’t done, I will admit I am nearing the closing moments of the IR stage, with only 1 last hurdle to overcome before I can transpile projects beginning -> end.

Here’s a small overview of what’s been done in the last two weeks (nah who am I kidding its all last night, I haven’t touched this in a bit)

Procedures

Katnip is scratch. Kinda. It transpiles to scratch. So it needs procedures.

I took a giant bite out of the huge problem that is procedures. It is very complex to try and emulate a return system in a program that just doesn’t support it.

Having taken a DSA class, this was a problem that I took to paper, and got the following solution:

  1. Stacks are beautiful.
    Let me elaborate. A stack is a structure that follows FiLo, or first-in, last-out. This is super important for returning from procedures, when considering the fact that a single variable will not be enough for systems when/if the function recurses. So this way, you push and pop on the stack to keep the order, and all return values are kept track of nicely!
  2. Mangled vars.
    Scope is a really hard concept to grasp, but even harder to emulate in a non-scoped language. For the most part, I want to keep Scratch’s inherent scope-less design, in the sense that variables can exist in similar ways. But I do want scopes. So I take back the before-last sentence.
    To do this, I mangle vars, allowing scopes to exist, multiple instances of the same code to run, and to have variables not collide.

For loops

A smaller sections, but still cool.

A for loop in scratch is a hidden–but supported–block. You can only iterate a variable, lets call it x, from 1..y inclusive, where y is the max range.

So for lists, this means lowering this:

for (x, myList) {
    looks.say(x);
}

into this:

for (x, listLength(myList)) {
    x = myList[x];
    looks.say(x);
}

Additionally, if doing a range function like this:

for (x, range(4, 10, 2)) {
    looks.say(x);
}

it lowers into this:

for (x, 3) {
    x = x * 2 + 4;
    looks.say(x);
}
2
0
12
Open comments for this post

2h 30m 52s logged

Site Selection

Finally got around to adding and implementing sites into Polaris! No longer are you land-locked to your current position, you can now plan ahead for other locations and times.

Sites

You can now have multiple sites, switch between them, and add them. Fully fleshed out menu

Lookahead

I moved to a 3-tab layout.

  1. Now
    A detailed overview of everything currently in the sky. Includes coordinates and other diagnostics for all objects in the sky, ranked using the algorithm
  2. Tonight
    A list view of all objects visible tonight. Less organized, as the algorithm that is used on tonight isn’t present
  3. Weeks ahead
    Looks 3 weeks ahead, and predicts what you will be able to see. Doesn’t take weather into account because our prediction models that far into the future suck.
0
0
16
Open comments for this post

1h 23m 12s logged

Finished lexer :P

Changes

  • Mini cli (kindaaaa just for testing atm)
  • Finished implementations of token handling for numbers, comments, and the other stragglers
  • Removed the raw"..." keyword in favor of a simpler-looking `...`
  • Smol error reporter because … its necessary idk 😭
0
0
6
Open comments for this post

2h 31m 16s logged

Lexer pt. 1

Background

After messing around in my other projects with regex, I came to the conclusion that regex is hard to read, and hrad to write. Lets fix that shall we?

Design

I want the language to feel simple, and ideally be simple under the hood. simple == !regex. For the whole run down on all of my keywords and symbols, check out the Token definition file.

But we both know you’re lazy, so heres a tl;dr rundown:

  • Define functions for sub patterns using parameters alongside a standard function shape: def dotted(part) = { part repeat { "." part } }
  • Define variable-esque patterns to reuse, so you don’t bloat your regex:
    let buildId = repeat 1.. { num}
  • Capture groups using the capture kward and use that output directly by importing the .grex file using a typescript import (yes really, no nrn, this lang is a WIP)
  • And SO SO SO much more. I highly recommend you read the token file.

Comparison

Don’t trust me? Adament on writing your own regex? Tell me what this regex means in 10 seconds:
^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*\W)(?!.*(?i:password))\S{12,}$
..
..
Yea no, thats near impossible. Now try this:

/** Secret must contain each class, avoid the obvious, and be 12+ non-space. */
pattern StrongSecret {
  start
  ahead { repeat { any } digit }
  ahead { repeat { any } ['a'..'z'] }
  ahead { repeat { any } ['A'..'Z'] }
  ahead { repeat { any } not word }
  notAhead { repeat { any } ignoreCase { "password" } }
  repeat 12.. { not space }
  end
}

You may be saying: “you cheated, you used a comment!”. Well, exactly. Regex doesn’t have comments. G-Rex does.

2
0
10
Open comments for this post

1h 6m 33s logged

YAY MATH

Jokes aside, this was one of the more fun and easy coding sessions I’ve had. I built most of the functions I needed, wrapping the astronomy library I use.

So it was just a culmination of cobbling together functions + iterating over them to form coherent graphs. They still look a bit off to me, but I will clean things up later. My focus is on finishing the demo, then going back.

Impl features list

  • Stubbed section for tonight/upcoming sections for sky diagnosis
  • Pill bar for time selection for graph display
  • Actual graph displaying altitude above horizon. Also includes grayed out bars for non-visible sections (not featured here, couldn’t get a good example)
0
0
28
Open comments for this post

11h 47m 38s logged

Recap

Aesthetic

My friend, a large astronomy enthusiast, pointed out that many apps have an entirely red mode to block out blue light, as it distorts vision when its most critical to seeing stars in the night sky or through a telescope. So I designed the entire app in shades of black and gray, with the intention of supporting a red-scale version with a very plug-and-play approach. Gray-scale ensured the app wouldn’t look horrendous when I switched to red.

DB

This is my first project with a database. I opted to use sqlite and learn all about how it works. Though much of the commands are based on stack overflow threads, and my understanding is still lacking, I plan to further and devlop this skill as I work on storage for users and pictures. This is definently an important part of an app like this.

Glass layout

This doesn’t really deserve its own section, but I thought it was interesting.

The cleanest apps imo are ones that use the system colors and design. So react-native was an obvious choice. However, liquid glass is an experimental feature, and furthermore requires packaging and building the react-native in a way that makes it near impossible to hot-reload using expo-go. For this reason, I opted to make my own liquid glass elements, pulling in the native ui library to apply it to elements of my own.

Astronomy logic

This is the core portion of the app. The main idea of the app is to engage users, and provide a constant influx of ideas and targets to see. It is hard for some to constantly have to look up what would be fun to see, with their equipment and location, and current weather.

Our app solves this by crunching all the data for this and displaying it in an easy-to-read format. We first calculate the different weather and astrological conditions at the time for the user. This involves calculating a multitude of values, but it all collapses into a single equation: score: reasons.length === 0 ? 0.5 + quality / 2 : (quality / 2) * 0.5 where quality is based off headroom and moonroom, and the other weather conditions (pulled from a local weather api)

0
0
64
Open comments for this post

6h 22m 44s logged

Project depth increase

Retrospectively, this probably should’ve been multiple seperate posts. But I forgot. Again.

Return statements

For compiling to scratch, a variety of different appracohes have been done. Personally, these fall under a few distinct approaches: variable and list. Variable is simply setting a variable to the output, whereas a list is just a stack following LiFo rules.

A variable should be used for single value, non-recursive functions. It’s pretty naive actually. The better alternative way is to use a stack, in which you push and pop from it. This way, you know the exact offset that correlates to the return value in recursive functions.

The stack also allows for easy nesting of functions next to each other, like foo(1, 2) + foo(3, 4), which is only possible in variable form with temporary vars.

Vscode Autocomplete

Less said here, but this was actually pretty simple. I just ran some regex to get all the identifiers, and then seperated them by type. Pretty rudamentry, but nice.

Scratch Defs

This was a huge first step in the IR design. Basically, I need a good way of storing metadata. Inventing whole new katnip syntax for this would:

a. Look bad, but also
b. Be horrible to implement

So I wrote a typescript file that takes care of the json metadata, allowing only rudamentry tags and opcode to be stored in Katnip portion.

Imports

This was a fun portion to tackle. Because I am targeting 3 deployments: vsc, cli, and web, I need a design that covers all 3. A friend suggested callbacks. This allows me to assume the user will define a function that allows filesystem interactions, without me touching a thing.

So all I did was bring in the code from the imported file, and ran compilation over it too. I pulled it in during the semantic analysis phase as that was the correct timing; after verifying the import statement; before the codegen.

Structs

Lots of deliberation occured here. It was very crucial to implement this, personally, because I use this type of feature (self-implemented, each time) in scratch. It always felt like a thing that I needed.

I was torn between strided and parallel list storage for the pieces of it. Strided was cool, and was more efficient with space and project list bloat, but in the end parallel lists were just SO much cleaner.

0
0
12
Open comments for this post

5h 43m 33s logged

Bugfixes + webprep

This will be a shorter devlog, because, though there is a lot of time logged, much of this was just troubleshooting the few things I was adding.

Bugfixes:

  • In the lexer, there existed some issues with my fsm, and the way I processed escaped characters
  • Added some protections in the parser instead of semantic analysis so enforcement was throurough and non-manual

Webprep:

  • Removed external dependencies that only npm could run. This enabled the beginning of development of a web editor gui by my friend in Svelte
  • Rewrote dependencies and npm-specific stuff to my npm-agnostic, using my own implementations (mostly just pico-colors tbh)

The photo attached is it showing how another runtime (in this example, bun) can run the project that originally only worked with npm.

0
0
12
Open comments for this post

1h 41m 23s logged

Just added my first addition!

Today I worked on learning the basics of go, the syntax, and how functions worked. I have a lot of prior coding experience, so this was nothing new.


I implemented ctrl+left-arrow and ctrl+right-arrow bindings today, allowing for easier and more ergonomic movement.

0
0
4
Ship

I made the semantic analysis portion to a custom coding language for scratch. It aims to bridge the gap for kids between code blocks and real scripting. It has full type safety, and a variety of different language components, creating a rich and immersive transition from scratch into the real world of programming. It has both simple syntax but also allows a high skill ceiling with more complex syntax.

I struggled a lot, spending hours on end chatting with programmers I am friends with, crafting a lot of these language decisions in late night chats. Every single step has been deliberately taken.

I am proud of the consistency and quality of the code I wrote. I feel proud to have made this section, and hope that by shipping (and hopefully the community receiving it well) I will be able to continue forwards to finishing the IR and code gen.

Since there isn’t a best way to use a programming language, I suggest both installing the npm package and the vscode extension (search ‘Katnip’ in the store). This will give you in-editor syntax highlighting and typechecking. Feel free to use the cli for lexing, parsing, and type checking.

  • 6 devlogs
  • 25h
  • 19.56x multiplier
  • 441 Stardust
Try project → See source code →
Loading more…

Followers

Loading…