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

b1j2754

@b1j2754

Joined June 19th, 2026

  • 14Devlogs
  • 4Projects
  • 1Ships
  • 15Votes
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
20
Open comments for this post

11h 45m 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
60
Open comments for this post

6h 22m 30s 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
5
Open comments for this post

5h 39m 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
6
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
2
Ship Pending review

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
  • 22h
Try project → See source code →
Open comments for this post

8h 59m 34s logged

Phase 2 complete (plus a lil extra)

Phase 2

Function overloads

This was an interesting task to take on. I had to first figure out how to match a function’s signiture to its call. I couldn’t simply check if a signiture existed or not, I had to check which variation it satisfied. This involved reworking the way I stored signitures, and allowed a single object to hold them all for a certain function name. This way, it was a lot cleaner and put together.

STDLIB

After working through the project, I realized that I needed a way to define the primitive blocks used in Scratch. I didn’t think adding them in as a Typescript object was elegant, and it definently wasn’t extendable. Instead, I opted to expand the language syntax to allow generics, and therefore enable modular and clean code in the form of a katnip-defined STDLib.

Katnip LSP

This section is less in depth, because the setup wasn’t as hard. I look up some docs, and most of it was drag and drop. There exists a single file for defining the regex expressions with which to color the words on the page, and then I connected my error reporter to the lsp’s standard error reporter to further enhance the experience. Every 300ms or so, it updates, and tells the user where the errors are, just like any other language supported in text editors.

0
0
2
Open comments for this post

4h 42m 40s logged

Almost completed phase 2 of the Semantic Analysis


Today I built a wide variety of things. But 3 specific features.

  1. visit(node: StatementNode): void
    This function parses all of my nodes. It covers variable assignment, sprite declaration, etc etc. It has many jobs, including entering scopes, declaring bodies, and following each AST-node stack recursively. Some are left stubbed out, as I spent most of my time on #2:

  2. inferType(expression: ExpressionNode): InternalType
    This function is ~200loc. It covers a wide variety of cases, all pertaining to the type inference of an expression AST. It not only infers the type, but recursively builds an internal model of what the user has written. So a type of list<dict<num, str>> becomes the stored internal representation of:

{
    kind: "list",
    element: {
        kind: "dict",
        key: {
            kind: "primitive",
            name: "num"
        },
        value: {
            kind: "primitive",
            name: "str"
        }
    }
}

Though it is a lot more complex than that, that’s what it boils down to. And lots and lots and lots of error statements.

  1. InternalTypes itself
    I built a system that stores the type state, with a few extra helper functions: isAssignable and typeToString. The former recursively traces both types and ensures total match. This means that a variable of type to could be assigned to a value of type from. The latter is just a pretty-print function for pretty errors to see what types were being looked at/expected at certain parts of the code.
0
0
1
Open comments for this post

3h 39m 56s logged

Finished phase 1 of the Semantic Analysis


Implemented Scope-Analysis checks. It can correctly identify and point out issues with scopes. It understands a variety of different scopes, from for-loops to functions to Sprites.


Also added support for switch-statements. Importantly, I chose to force only 1 default, and force it to be only at the end.


I also implemented true and false as a new Boolean primitive type, alongside a true return statement

0
0
1
Open comments for this post

2h 49m 52s logged

2. Building Semantic Analysis

This will be shorter, since most of what I say is better just written in code.
The main idea is two passes:

  1. Hoist
    Bring procedures to the top to allow forward references. I explain why I did so above.
  2. Visit
    Acctually go through and validate. This is the main core bit of the semantic analysis portion.

I am a little stuck at a desgin fork. Should I allow scripts inside no ‘Sprite’ Scope to be there? Or should I force them into the Stage. Or do I error?
Scratch-like behaviors tell me that it should go to stage, but that feels tacky and wrong.


  • Can functions be public? I think so. Can’t be temp.
  • Need to make start and end possibly null
  • Make function be able to be public/private. Assumed private
  • Everything at the root of a file should be invalidated. The space should be reserved for imports, functions, global stuff.

Overall, I worked on building semantic analysis, at least the basic parts. I added variable decleration handling in scopes, and all of expressionstatement parsing.

0
0
1
Open comments for this post

1h 7m 57s logged

Semantic Analysis Planning

Currently trying to think about how best to implement semantic analysis. I can’t lie, I am just getting back into this project, so I am rediscovering what I had previously written.I guess I have to start at the beginning. What is semantic analysis?

  1. Type Checking   
    • Operations need to be with compatible data types   
    • One note to myself here is that I have reserved functions because it’s Scratch, so those need to have a designed store for their types2. Scope Resolution   
    • Make sure variables and functions are designed in the right parts of code   
    • I think this will cover imports too, but its worth thinking about   
    • Undeclared and redeclared variable checks
  2. Function Call Validation   
    • I’ll have to go back and check if I accidentally covered that in the parser, but I believe this should go here
  3. Flow Control   
    • Switch case validations, make sure fall through keywords and default cases etc. are all in valid places5. Reserved Keyword   
    • Check if variable and functions defined are conflicting with Katnip’s

First I’m going to do symbol collection and scope resolution.
One important nuance I discovered was whether or not to enforce scope declaration. Should there be an inferred scope?
In Scratch, this inferred scope is mostly ‘Public’, as variables are shared across sprites. However, I think I am going to flip this, as it feels wrong to teach the user that variables work across sprites.


Thought dump:

  • ‘Private’ kward can’t be used at root level (stage). Can’t be used as modifier for sprite either, tho neither should any modifier.
  • Scope-less definitions are okay. Scratch does this, just opposite of me.
  • I am going to raise function declarations so that they can be referenced before making. Requires 2 passes, but seems simpler and more intuitive in my opinion.
  • I am going to allow function overloading. It seems useful, and I like the way Java does it.
0
0
3
Open comments for this post

4h 31m 41s logged

So much progress.

I added a small script to generate felt variations for hue variations every 10deg, which improves app loading time. I’m still trying to optimize the loading of so many assets, but it seems faster than applying a hue transformation on tons of elements in real time.

I added a card carousel element (see image) and successfully added some card to it. Probably not the final form, but it seems pretty good for now.

Another huge improvement was implementing my own tab bar. Though it appears a little off–as I’m still working out the kinks of the (+) icon being set up a bit, I think it looks better than the plain white rectangle I previously had. Still working on making it glide smoothly though, I’m looking into some animation libraries and grabbing them.

Tried implementing themes too, but it seems to early to do so. I ended up writing 3 different versions and hated them all. I refactored lots of code unneccassarily, so I just reverted a lot of the changes.

Overall lots done, hopefully going to finish the rough draft of the app today!

0
0
3
Open comments for this post

2h 49m 53s logged

I just finished adding the threaded border around my app cards. Though it looks simple, it was surprisingly difficult to add. React Native seems to have a longterm bug (an issue for it is present on github) where rounded corners alongside a dashed pattern for the border css property of an element breaks. It just becomes a solid-lined square.

So the only solution and workaround, as this was vital to its look, was to use svgs. So I used an svg rect with all the attributes I needed and molded it to the shape. I spent a solid few hours debugging this, as it wouldn’t show. Finally, I found out that Tamagui’s view element does not seem to initialize with a width nor height, meaning it would initialize an element holder with those attributes set to undefined. I also had incorrectly reffered the attributes as .w and .h instead of their lengthier counterparts.

In summary, it was a hard, but very crucial experience, learning to be careful with mixing on library elements and workarounds for things that don’t exist.

0
0
1
Open comments for this post

2h 52m 30s logged

I finished adding a small tab navigation ui to my app. It took a while to figure out how to link tamagui with expo, but after a few tutorials online (very elusive) I finally found out how to set it up. Its as simple as running npx create-expo-app@latest my-app and then npm install tamagui @tamagui/config. I actually switched to using expo-stack, but then ultimately changed a lot of files.

I also learned how to make my own components, creating a felt-like texture, and then adding a ‘raised’ element that I could use. There is a huge issue though, which has plagued me for the past 2ish hours: expo go, or at least within my speicific app, won’t render boxshadows that are out-set. You can see in the screenshot that the corners are the only part that are rendered. Using online Snack + Expo Go demo yields a working version, but it won’t work on mine right now.

Tomorrow ill try prebuilding and see if expo-go is the issue. Maybe a true apk will solve it. But thats a temporary fix, as I need fast changes to rapidly learn and iterate.

EDIT: Holy moly I did it. Sometimes a nap is the solution. The issue is that my felt custom element didn’t have the corner radius and overflow attributes set. For some reason–I assume because I’m tiling the bg–it prevented the boxshadow from rendering.

0
0
2

Followers

Loading…