Max + TypeScript Starter Project (esbuild support, modular, WIP)

Oluf Andrews's icon

Hi everyone

I've been working on a TypeScript starter framework for Max and Max for Live development. It’s something that I built to streamline my workflow and its become part of my regular toolset. I hope that it might be useful to others working with js in Max who want modern tooling, better structure, or just an easier way to manage growing projects.

It's mildly opinionated, but I don't think there's anything that diverges too much from community standards on either the Max or TS dev sides. I just tried to mash together both worlds in as clean a way as possible. With IDE integration (I use webstorm), code build and deploy to my Max project is down to one button press.

What it is:

  • TypeScript support for Max's JS engine (v8 object)

  • esbuild-based build system with per-file build directives (currently only on the dev branch)

  • Clean separation between source, compiled code, and Max project folders.

This is still a work in progress — the main branch currently uses tsc, and as mentioned above, dev branch uses esbuild as default.

I'd appreciate feedback if anyone tries this. I haven't hit any insurmountable issues yet, and it works with my workflow, but I'd love to hear about any deficiencies or issues with other workflows and usage patterns.

Let me know if you give it a try or run into any issues. Always happy to iterate.

Oluf

TFL's icon

Thanks for this! Makes me want to eventually take the time to learn Typescript. Currently reading the official ts get started guide, and I'm wondering if there's any reason why you define Dict, Fold and LiveAPI types as class instead of interfaces?

By the way, I just found what seems a rather complete typescript definition of all max-specific js objects. It's part of the DefinitelyTyped repo and there's this other repo providing how-to examples.

All this don't seems to be updated for Max 9/v8, but still look like a solid starting point for a more exhaustive type definition.

Oluf Andrews's icon

Thanks for checking it out!

I used class instead of interface because these are constructable objects at runtime, not just type contracts. An interface would just describe their shape, but wouldn't, for example, let me call 'new Dict(...)'.

I had spent some time looking for typedef libraries or projects that I could integrate with, and was considering the library on definitely typed. There's a lot of great work there, but decided to, at least for now, build this out separately. Selfishly, it's a great learning opportunity for me, and I can slowly build out the defs as I go - I'm not in a rush, and I don't have the capacity for much more right now. But if this ever gets updated, or I have the time in the future, then I'm definitely not ruling out going with that in the future.

TFL's icon

I used class instead of interface because these are constructable objects at runtime, not just type contracts. An interface would just describe their shape, but wouldn't, for example, let me call 'new Dict(...)'.

Could you elaborate on this? I understand interface just define shapes/types and classes are constructable objects, but I don't get why you need to re-define classes that already exist in the realm of js/jsui/v8/v8ui. I mean I can already create a new Dict() without having to create that class myself. By re-reading your code I just realized I missed the declare part of it, and I realize that the Definitely typed code does the same (declare class Dict{}) , although not in a global scope.

I'll read in the typescript doc how these declare work, but I'm wondering why you use that global scope unlike the Definitely typed version.