Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
# Jam Tools

Create your own music performance system with Jam Tools. See the [docs](https://jam.tools) for more information.

Getting started is easy using the [create-springboard-app](https://jam.tools/docs/springboard/cli/create-springboard-app) CLI:

```shell
npx create-springboard-app --template jamtools
```
13 changes: 12 additions & 1 deletion doks/assets/scss/common/_custom.scss
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
// Put your custom SCSS code here

.default-embed {
max-width: 500px;
margin: 0 auto;
}

.default-embed iframe {
width: 100%;
aspect-ratio: 16 / 9;
border: none;
}

svg[data-bs-theme-value="dark"], svg[data-bs-theme-value="light"] {
display: none !important;
}
Expand Down Expand Up @@ -55,7 +66,7 @@ svg[data-bs-theme-value="dark"], svg[data-bs-theme-value="light"] {
@media(prefers-reduced-motion:no-preference) {
.marquee-content {
animation-name: scroll;
animation-duration: 2 5s;
animation-duration: 25s;
animation-timing-function: linear;
animation-iteration-count: infinite;
animation-play-state: running;
Expand Down
4 changes: 4 additions & 0 deletions doks/config/_default/hugo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ pagerSize = 10
rssLimit = 10
summarylength = 20 # 70 (default)

[security]
[security.funcs]
getenv = ['^HUGO_', '^CI$', '^RYBBIT_']

# Multilingual
defaultContentLanguage = "en"
disableLanguages = ["de", "nl"]
Expand Down
11 changes: 5 additions & 6 deletions doks/config/_default/menus/menus.en.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,10 @@
# url = "/docs/1.0/prologue/introduction/"
weight = 10

# [[main]]
# name = "Blog"
# url = "/blog/"
# weight = 30
[[main]]
name = "Blog"
url = "/blog/"
weight = 30

# [[social]]
# name = "X"
Expand All @@ -54,7 +54,7 @@
[[social]]
name = "GitHub"
pre = '<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-brand-github" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M9 19c-4.3 1.4 -4.3 -2.5 -6 -3m12 5v-3.5c0 -1 .1 -1.4 -.5 -2c2.8 -.3 5.5 -1.4 5.5 -6a4.6 4.6 0 0 0 -1.3 -3.2a4.2 4.2 0 0 0 -.1 -3.2s-1.1 -.3 -3.5 1.3a12.3 12.3 0 0 0 -6.2 0c-2.4 -1.6 -3.5 -1.3 -3.5 -1.3a4.2 4.2 0 0 0 -.1 3.2a4.6 4.6 0 0 0 -1.3 3.2c0 4.6 2.7 5.7 5.5 6c-.6 .6 -.6 1.2 -.5 2v3.5"></path></svg>'
url = "https://github.com/jamtools/jamtools"
url = "https://github.com/jamtools/springboard"
post = "v0.1.0"
weight = 30

Expand Down Expand Up @@ -82,4 +82,3 @@
# name = "Terms of Service"
# url = "/terms/"
# weight = 20

10 changes: 5 additions & 5 deletions doks/config/_default/menus/menus.nl.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,15 @@
url = "/docs/prologue/introduction/"
weight = 10

# [[main]]
# name = "Blog"
# url = "/blog/"
# weight = 20
[[main]]
name = "Blog"
url = "/blog/"
weight = 20

[[social]]
name = "GitHub"
pre = "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"feather feather-github\"><path d=\"M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22\"></path></svg>"
url = "https://github.com/jamtools/jamtools"
url = "https://github.com/jamtools/springboard"
post = "v0.1.0"
weight = 10

Expand Down
2 changes: 1 addition & 1 deletion doks/config/_default/params.toml
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ mainSections = ["docs"]
editPage = false # false (default) or true
lastMod = false # false (default) or true
repoHost = "GitHub" # GitHub (default), Gitea, GitLab, Bitbucket, or BitbucketServer
docsRepo = "https://github.com/jamtools/jamtools"
docsRepo = "https://github.com/jamtools/springboard"
docsRepoBranch = "main" # main (default), master, or <branch name>
docsRepoSubPath = "" # "" (none, default) or <sub path>

Expand Down
101 changes: 101 additions & 0 deletions doks/content/blog/background/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
---
title: "Background on Jam Tools"
description: "Jam Tools application and framework background"
summary: ""
date: 2024-12-02T14:38:33+02:00
lastmod: 2024-12-02T14:38:33+02:00
draft: false
weight: 50
categories: []
tags: []
contributors: []
pinned: false
homepage: false
seo:
title: "" # custom title (optional)
description: "" # custom description (recommended)
canonical: "" # custom canonical URL (optional)
robots: "" # custom robot tags (optional)
---

I've been wanting to have a public journal for my current efforts of software development, so here it is.

Right now I'm focusing on 2 projects:

- [Jam Tools](https://jam.tools) - An ecosystem of software development tools to build cross-platform multiplayer MIDI applications
- [SongDrive](https://songdrive.app) - An online songwriting and collaboration platform

This post is about Jam Tools, more specifically about the application framework [Springboard](https://docs.jam.tools/springboard/overview) and [Jam Tools Core](https://docs.jam.tools/jamtools/overview) (additional code to make it easy to work with MIDI and IO devices). You can check out the [repo](https://github.com/jamtools/springboard) for more info. The project is open-source to enable developers to make their own MIDI applications, and also collaborate together on features to include into a common application.

Jam Tools was created with an interest in making a realtime music communication tool that allows musicians to communicate thoughts to each other while playing music (The Jam App). It's meant to be used with everyone in the same room, and ideas can be circulated among different phones and screens in the room. The goal is to communicate chord progressions, lyrics, and messages such as "slow down" or "let's play something funky". It also helps automate [MIDI](https://en.wikipedia.org/wiki/MIDI)-related processes and control [WLED](https://kno.wled.ge) lighting.

Here are some videos from *previous* implementations before starting on the current project. There were lots of learnings from writing this code that contributes to the design of Springboard now. I think the videos capture the spirit of what I'm trying to make.

<details>
<summary>Demo Videos</summary>

- Jam Tools live demo with MidiCrash - Control synth chords and lights with crash cymbal. [Code](https://github.com/jamtools/springboard-local/tree/main/shared/application_mode_managers/adhoc_chord_mode)

{{< youtube-custom id="mYMZ2E7LKQI" >}}

---

- MidiCrash - Use a real crash cymbal as a MIDI trigger. [Code](https://github.com/jamtools/midi-crash)

{{< youtube-custom id="DdHDOOWZTPY" >}}

---

- Jam Tools live demo - Control chords and lights with MIDI drum controller. [Code](https://github.com/jamtools/springboard-local/blob/main/shared/application_mode_managers/progression_mode/progression_mode_manager.ts)

{{< youtube-custom id="UII4HS0Vb9Q" >}}

</details>

---

Back to the project - One thing the Jam App requires is using a phone/tablet to remotely control something on a separate computer that has the MIDI devices plugged in (i.e. a phone communicating with a desktop app hosting a local server). From experience of trying to build this program a few times, in order for this to scale this means there needs to be high cohesion between the UI code running on the phone, and the feature-level code related to MIDI functionality running on the server. Another required feature is the application to optionally run standalone in the browser, so you can do everything on the phone in isolation. Given these constraints, the application needs to run in multiple different deployment contexts, such as:

- Browser local/offline
- Browser with server

At the time of writing, there is also active development to support the following:

- Desktop app local/offline
- Desktop app online with remote server
- Desktop app with local server
- Desktop app online with remote server, and local server
- Mobile app local/offline (iOS has not implemented Web MIDI yet... which is why this is necessary)
- Mobile app with remote or local server

Because of these requirements, the project has since turned into a framework for creating cross-platform applications, with an emphasis on isomorphic TypeScript code (through using JSON-RPC behind the scenes), which helps with the cohesion of UI and MIDI-related code. The framework should allow for compiling into all of these formats with "zero config", like the DX of [Parcel](https://parceljs.org), and require a minimal amount of feature-level Typescript code to implement the given application's features.

Each app compilation consists of a "platform entrypoint" (usually provided by the framework and used by the framework by default, for the given platform/spec being compiled), and an "application entrypoint", where multiple [modules](https://docs.jam.tools/springboard/module-development) will make up a given app's features. All platform deployments can share the same application entrypoint, which is what makes the code cohesive.

---

##### Desktop

For desktop app compilation, the framework uses [Tauri](https://v2.tauri.app). The local server portion is currently being implemented with a [Node.js sidecar](https://v2.tauri.app/learn/sidecar-nodejs), though we may go in the direction of utilizing Rust for the local server hosting and relaying RPC calls to the Tauri webview process, and potentially not require the sidecar at all. I like the security model of Tauri's ecosystem, and having the node sidecar kind of messes that up. I'm also considering using Deno since it similarly supports explicit security features and compiles to binary directly, so tools like pkg won't be necessary in that case. But it still adds another asset to be signed/reviewed/shipped, which is a liability. So I think going with rust for network functionality is the way to go. Having the sidecar also makes things more difficult to debug. I was originally thinking that doing MIDI stuff in its own process would have lots of performance benefits, but I think it would perform fine in the webview process, as long as the UI isn't doing fancy/expensive things during midi operations. In the case where we need to optimize performance there, we should be able to use a separate invisible Tauri webview for optimizing midi/audio performance.

##### Mobile

For mobile app compilation, the framework uses [React Native](https://reactnative.dev) and [Expo](https://expo.dev). The compiled mobile app's UI is shown via an embedded webview, which has access to React Native functions through the Springboard RPC system. This way we can utilize all of React Native's ecosystem, while creating a [Web Native App](https://ionic.io/resources/articles/what-is-web-native) with React as the underlying view layer in both contexts. Great flexibility with no code required in the application to wire things up.

##### Server

We're also planning to support [Cloudflare Workers](https://workers.cloudflare.com) and [PartyKit](https://www.partykit.io) for turnkey room-isolation. The infrastructure at CloudFlare is pretty affordable, scalable, developer-friendly, and is built on Web Standards. Using PartyKit, a running app is compartmentalized into a specific room, so things like game lobbies and sessions for a particular game implementation can be more straightforward to segment and scale in a given project. In this case, PartyKit is solving something that I think Springboard should also directly support as far as managing the data of that room, which is the idea of something I'm currently defining as "Spawnables" (or "Snacks"). It would likely "feel" like defining a module though it has its own managed instance state, and is meant to be arbitrarily allocated in server state, like the PartyKit room does for us when it creates a new room. Spawnables can also be used as a more low-level thing, like instantiating a VST plugin-like object in some midi/audio pipeline context, that has some UI and state associated with it when it's spawned by the user.

---

The plan is to have multiple zero-config managed workflows to create these applications without downloading the needed build tools to do so, by utilizing GitHub actions, and a `create-springboard-app` command that populates a new project with a bunch of GitHub action workflows, each referencing reusable maintained versions of the workflows. Then you can create desktop and mobile apps and deploy your app to a cloud provider by simply pushing tags to a new project, or any other appropriate workflow trigger.

The generic application framework described above is published on npm as [`springboard`](https://github.com/jamtools/springboard/tree/main/packages/springboard/core) and [`springboard-cli`](https://github.com/jamtools/springboard/tree/main/packages/springboard), whereas the code to make MIDI-related features is in [`@jamtools/core`](https://github.com/jamtools/springboard/tree/main/packages/jamtools/core). The main currently available MIDI features are in the [Macro](https://docs.jam.tools/jamtools/macro-module) module.

The project is open-source to enable developers to make their own MIDI applications, and also collaborate together on features to include into a common application. Feel free to join the Jam Tools [Discord server](https://jam.tools/discord) to join the conversation, or subscribe to the [newsletter](https://jamtools.kit.com/2b15625d04).

Thanks for reading!

Here's a relevant presentation on the framework:

{{< youtube-custom id="_DrV000Se7M" >}}
2 changes: 2 additions & 0 deletions doks/content/docs/introduction/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ The framework behind Jam Tools applications consists of the following components
- [Springboard](../../springboard/overview) - Full stack React framework that supports compilation into multiple server and client platforms
- [Jam Tools Core](../../jamtools/overview) - Functionality on top of Springboard related to interacting with MIDI and IO devices

Check this [blog post](/blog/background-on-jam-tools) for more background on the framework.

---

Most of what's on this docs site does not pertain to MIDI applications specifically, as all of the generic application features are available for use in any application. Though the inception of these tools are to develop powerful multiplayer MIDI applications, so examples will typically include how to incorporate MIDI instruments for a given feature.
Expand Down
6 changes: 3 additions & 3 deletions doks/content/docs/introduction/quickstart.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,10 +103,10 @@ springboard.registerModule('Main', {}, async (moduleAPI) => {
8. Mess around with changing the code in `src/index.tsx` to do other things. You can:
- Try more purposeful [macro types](/docs/jamtools/midi/macros) that can have a more intentional experience for the user.
- Change the styling of the Macro editors to your liking using CSS.
- Add UI elements to interact with your DAW from your phone. A simple example of this here: [https://github.com/jamtools/easy](https://github.com/jamtools/easy)
- Add UI elements to interact with your DAW from your phone. A simple example of this here: [https://github.com/jamtools/daw-easy-button](https://github.com/jamtools/daw-easy-button)

9. If you'd like to discuss the UX around using macros, please comment on [this issue](https://github.com/jamtools/jamtools/issues/24). To report an issue or request support for other macro types, [submit an issue](https://github.com/jamtools/jamtools/issues/new).
9. If you'd like to discuss the UX around using macros, please comment on [this issue](https://github.com/jamtools/springboard/issues/24). To report an issue or request support for other macro types, [submit an issue](https://github.com/jamtools/springboard/issues/new).

Nice job! You've built your first Jam Tools app. Next you can learn about:
- [Deploying as a desktop app](/docs/springboard/platforms/desktop-app)
- [Deploying as a desktop app that hosts the UI for local devices](/docs/springboard/platforms/desktop-app)
- [Creating your own modules](/docs/springboard/module-development)
4 changes: 2 additions & 2 deletions doks/content/docs/springboard/module-development.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,14 @@ Modules can play a few different types of roles:

When registering a module, the module provides a callback to run on app initialization. The callback the module provides essentially _is_ the module. The callback receives an instance of the `ModuleAPI`. The namespacing of states and actions for this particular module are automatically managed by the framework. Some useful methods/properties from the `ModuleAPI` are documented in the [ModuleAPI docs](../typedoc_docs/module_api/classes/ModuleAPI.md).

Check out the [Tic-Tac-Toe example](https://github.com/jamtools/jamtools/blob/main/apps/small_apps/tic_tac_toe/tic_tac_toe.tsx) and [Song Structure example](https://github.com/jamtools/jamtools/blob/main/packages/jamtools/features/modules/song_structures_dashboards/song_structures_dashboards_module.tsx) for examples of feature modules.
Check out the [Tic-Tac-Toe example](https://github.com/jamtools/springboard/blob/main/apps/small_apps/tic_tac_toe/tic_tac_toe.tsx) and [Song Structure example](https://github.com/jamtools/springboard/blob/main/packages/jamtools/features/modules/song_structures_dashboards/song_structures_dashboards_module.tsx) for examples of feature modules.

## Writing a utility module

By default it is assumed a module is a feature or initializer module, meaning it is assumed that the module does not expose anything for other modules to use. In order for other modules to be aware of any exposed functions/properties, we need to perform [interface merging](https://www.typescriptlang.org/docs/handbook/declaration-merging.html#merging-interfaces) to register the module's return value with the Springboard framework's module system.

Here's an [example](
https://github.com/jamtools/jamtools/blob/cea35258c6d7e495a68148c4a9e61ac06dcca609/packages/jamtools/core/modules/macro_module/macro_module.tsx#L31-L35) of the Macro module declaring its return type:
https://github.com/jamtools/springboard/blob/cea35258c6d7e495a68148c4a9e61ac06dcca609/packages/jamtools/core/modules/macro_module/macro_module.tsx#L31-L35) of the Macro module declaring its return type:


```ts
Expand Down
2 changes: 1 addition & 1 deletion doks/content/docs/springboard/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ Springboard is a modular cross-platform application builder and runtime library

This dual requirement has shaped how the framework works, by maximizing the amount of code reuse across the different platforms, and utilizing JavaScript isomorphism as much as possible.

Springboard uses the concept of [modules](/docs/springboard/module-development) to encapsulate responsibilities of different pieces of code. A new Springboard application contains no modules by default. There are some predefined modules that you can import into your code, namely the modules defined by the [`@jamtools/core`](https://github.com/jamtools/jamtools/tree/main/packages/jamtools/core/modules) package at the time of writing.
Springboard uses the concept of [modules](/docs/springboard/module-development) to encapsulate responsibilities of different pieces of code. A new Springboard application contains no modules by default. There are some predefined modules that you can import into your code, namely the modules defined by the [`@jamtools/core`](https://github.com/jamtools/springboard/tree/main/packages/jamtools/core/modules) package at the time of writing.

Each application build for a given platform consists of two parts:

Expand Down
Loading
Loading