fragment icon indicating copy to clipboard operation
fragment copied to clipboard

feat: add TypeScript support

Open FabienMotte opened this issue 2 years ago • 3 comments

Summary

This PR adds TypeScript support for Fragment sketches.

Since Fragment uses Vite behind the scenes (which already supports TypeScript transpilation via esbuild), TypeScript support is pretty straightforward to add.

Result

  • The CLI now accepts sketch files with a .ts extension, for example: fragment ./sketch.ts --new.
  • Templates are available in TypeScript version, you just need to add -ts at the end of the template name: fragment ./sketch.ts --new --template=2d-ts.
  • tsconfig.json file is created automatically for you with the right paths when you create a new sketch based on a TypeScript template.
  • All sketch exports are typed and can be imported from @fragment/types. You just need to pass your current sketch rendering as a generic to lifecycle functions to have the proper types, for example: Init<"2d">.
  • Props are also typed thanks to a helper function typedProps.
  • TypeScript modules have been added for GLSL files (.glsl, .vs, .fs, .vert, and .frag).

Demo

https://user-images.githubusercontent.com/662153/188423546-4e600187-cb86-4e42-a3d4-e796f9b8d76b.mov

Code sample

import { onControlChange } from "@fragment/triggers";
import { typedProps } from "@fragment/types/helpers";
import type {
  Init,
  Update,
  Resize,
  FilenamePattern,
  Name,
  Fps,
  Duration,
  Rendering,
} from "@fragment/types";

export let props = typedProps({
  number: {
    value: 50,
    hidden: false,
    onChange({ value }) {
      console.log(value);
    },
    params: {
      min: 0,
      max: 100,
      step: 0.1,
    },
  },
});

export let init: Init<"2d"> = ({ context, width, height }) => {
  onControlChange(18, (event) => {
    props.number.value = event.value * 100;
  });
};

export let update: Update<"2d"> = ({ canvas, context, width, height }) => {
  context.clearRect(0, 0, canvas.width, canvas.height);
  context.beginPath();
  context.arc(width * 0.5, height * 0.5, props.number.value, 0, Math.PI * 2);
  context.fillStyle = "red";
  context.fill();
};

export let resize: Resize<"2d"> = ({ context, canvas, width, height }) => {
  context.clearRect(0, 0, canvas.width, canvas.height);
};

export let rendering: Rendering = "2d";
export let duration: Duration = 1;
export let fps: Fps = 60;
export let name: Name = "test";
export let filenamePattern: FilenamePattern = ({ filename, suffix }) =>
  `${filename}.${suffix}`;

FabienMotte avatar Sep 05 '22 10:09 FabienMotte

Thanks for this detailed PR @FabienMotte!

There's a few changes I'd like to request and I also have a few questions since I have very little experience with Typescript:

  • In the CLI docs, I find it a bit confusing to have both example with and without typescript following each other. I'd rather have two <code> block, the first one left untouched and a second one with just a subtitle With typescript. It seems to me that beginners could misunderstand the command to type if you have no knowledge of what typescript is. If that's the case, you can just ignore the second block and focus on the first command.

  • Are type Duration, type Fps and type Name really needed ? I find it a bit confusing not to have just number or string in the templates. These are primitive data types, I'm wondering what the need for a additional layer here ?

  • Looking at package.json, I see that three and p5 are hosting their @types outside of the repository. Could it be done easily ? What's the pros and cons of that ?

And thanks for spotting the filename pattern issue in the docs where suffix was renamed timestamp, the docs were indeed not up to date!

raphaelameaume avatar Sep 07 '22 08:09 raphaelameaume

I merged some changes into dev which makes some types obsolete already, sorry 😄

  • "vec2" and "vec3" do not exist anymore, in favor of a generic vec fieldType. It also supports 4 dimensions vectors now, see #19 for details
  • ColorInput supports new kinds of values for hsl and also objects with r, g, b and optionnally a keys. See #20 for details

I also noticed that options seems to be missing in params types as I get an error when trying to create a select GUI by passing options to params.

Capture d’écran, le 2022-09-07 à 15 09 56

raphaelameaume avatar Sep 07 '22 13:09 raphaelameaume

  • In the CLI docs, I find it a bit confusing to have both example with and without typescript following each other. I'd rather have two <code> block, the first one left untouched and a second one with just a subtitle With typescript. It seems to me that beginners could misunderstand the command to type if you have no knowledge of what typescript is. If that's the case, you can just ignore the second block and focus on the first command.

I updated the docs to make the separation clearer between JS and TS. Don't hesitate to put yourself as a reviewer and ask for a change if that's not what you had in mind.

  • Are type Duration, type Fps and type Name really needed ? I find it a bit confusing not to have just number or string in the templates. These are primitive data types, I'm wondering what the need for a additional layer here ?

I removed those types, indeed, they are unnecessary.

  • Looking at package.json, I see that three and p5 are hosting their @types outside of the repository. Could it be done easily ? What's the pros and cons of that ?

I guess the answer is yes and would make more sense since Fragment is a JavaScript library. The typing should live on https://github.com/DefinitelyTyped/DefinitelyTyped as Three.js or p5.js are doing. I never published a package on this repo, so I would need to see how this can be done.

I merged some changes into dev which makes some types obsolete already, sorry 😄

No worries, I'll update those accordingly.

I also noticed that options seems to be missing in params types as I get an error when trying to create a select GUI by passing options to params.

Oops, good catch, totally forgot to include this type in the Prop union!

Thank you for your comments!

FabienMotte avatar Sep 07 '22 17:09 FabienMotte