Skip to content

Commit

Permalink
Implement Punctual target (wrapper, canvas, frame) (#322)
Browse files Browse the repository at this point in the history
Closes #316
  • Loading branch information
munshkr authored Jan 5, 2025
1 parent 8598956 commit b3dad73
Show file tree
Hide file tree
Showing 11 changed files with 574 additions and 10 deletions.
1 change: 0 additions & 1 deletion .prettierignore

This file was deleted.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
"scripts": {
"build": "lerna run build",
"check": "lerna run check",
"lint": "prettier -c .",
"format": "prettier -w ."
"lint": "lerna run lint",
"format": "lerna run format"
},
"keywords": [
"codemirror",
Expand Down
2 changes: 2 additions & 0 deletions packages/web/.prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
public
src/lib/punctual.js
4 changes: 3 additions & 1 deletion packages/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@
"prebuild": "node script/prebuild.js",
"build": "npm run prebuild && tsc && vite build",
"start": "node ./bin/flok-web.js",
"check": "tsc --noEmit"
"check": "tsc --noEmit",
"lint": "prettier -c .",
"format": "prettier -w ."
},
"dependencies": {
"@flok-editor/server-middleware": "^1.3.0",
Expand Down
31 changes: 31 additions & 0 deletions packages/web/src/components/punctual-canvas.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import React from "react";
import { cn } from "@/lib/utils";
import { DisplaySettings } from "@/lib/display-settings";

interface PunctualCanvasProps {
fullscreen?: boolean;
displaySettings: DisplaySettings;
ref: React.RefObject<HTMLCanvasElement>;
}

const PunctualCanvas = ({
fullscreen,
displaySettings,
ref,
}: PunctualCanvasProps) => (
<canvas
ref={ref}
className={cn(
"absolute top-0 left-0",
fullscreen && "h-full w-full block overflow-hidden",
)}
style={{
imageRendering: "pixelated",
display: displaySettings.showCanvas ? "" : "none",
}}
width={window.innerWidth / displaySettings.canvasPixelSize}
height={window.innerHeight / displaySettings.canvasPixelSize}
/>
);

export default React.memo(PunctualCanvas);
96 changes: 96 additions & 0 deletions packages/web/src/lib/punctual-wrapper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import { DisplaySettings } from "./display-settings.js";
import { ErrorHandler } from "./mercury-wrapper.js";
import { isWebglSupported } from "./webgl-detector.js";

// Based on https://github.com/dktr0/Punctual/blob/main/index.html
export class PunctualWrapper {
initialized: boolean = false;

protected _canvas: HTMLCanvasElement;
protected _punctual: any;
protected _animation: any;
protected _onError: ErrorHandler;
protected _onWarning: ErrorHandler;
protected _displaySettings: DisplaySettings;

constructor({
canvas,
onError,
onWarning,
displaySettings,
}: {
canvas: HTMLCanvasElement;
onError?: ErrorHandler;
onWarning?: ErrorHandler;
displaySettings: DisplaySettings;
}) {
this._canvas = canvas;
this._animation = null;
this._onError = onError || (() => {});
this._onWarning = onWarning || (() => {});
this._displaySettings = displaySettings;
}

setDisplaySettings(displaySettings: DisplaySettings) {
this._displaySettings = displaySettings;
}

async initialize() {
if (this.initialized) return;

if (!isWebglSupported()) {
this._onError("WebGL is not supported on this browser.");
return;
}

// @ts-ignore
const P = await import("./punctual.js");
const { Punctual } = P;

try {
this._punctual = new Punctual();
} catch (error) {
console.error(error);
this._onError(`${error}`);
return;
}

this._animation = requestAnimationFrame(this.animate);

this.initialized = true;
console.log("Punctual initialized");
}

animate = () => {
if (!this.initialized) return;

const nowTime = Date.now() / 1000.0;
this._punctual.preRender({ canDraw: true, nowTime });
this._punctual.render({ canDraw: true, zone: 0, nowTime });
this._punctual.postRender({ canDraw: true, nowTime });

this._animation = requestAnimationFrame(this.animate);
};

async tryEval(code: string) {
if (!this.initialized) await this.initialize();

try {
const res = await this._punctual.define({
zone: 0,
text: code,
time: Date.now() / 1000.0,
});
console.log(res);
} catch (error) {
console.error(error);
this._onError(`${error}`);
}
}

dispose() {
cancelAnimationFrame(this._animation);
this.initialized = false;
console.log("Punctual disposed");
}
}
5 changes: 5 additions & 0 deletions packages/web/src/lib/punctual.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
declare module "./punctual.js" {
export class Punctual {
constructor();
}
}
324 changes: 324 additions & 0 deletions packages/web/src/lib/punctual.js

Large diffs are not rendered by default.

97 changes: 97 additions & 0 deletions packages/web/src/routes/frames/punctual.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import { useEvalHandler } from "@/hooks/use-eval-handler";
import { useSettings } from "@/hooks/use-settings";
import { sendToast } from "@/lib/utils";
import { isWebglSupported } from "@/lib/webgl-detector";
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { defaultDisplaySettings } from "@/lib/display-settings";
import { PunctualWrapper } from "@/lib/punctual-wrapper";
import PunctualCanvas from "@/components/punctual-canvas";

declare global {
interface Window {
m: number; // meter value from Mercury
}
}

export function Component() {
const canvasRef = useRef<HTMLCanvasElement | null>(null);
const hasWebGl = useMemo(() => isWebglSupported(), []);
const [instance, setInstance] = useState<PunctualWrapper | null>(null);
const [displaySettings, setDisplaySettings] = useState(
defaultDisplaySettings,
);

useEffect(() => {
if (hasWebGl) return;
sendToast(
"warning",
"WebGL not available",
"WebGL is disabled or not supported, so Hydra was not initialized",
);
}, [hasWebGl]);

useEffect(() => {
if (!hasWebGl) return;
const canvas = canvasRef.current;
if (!canvas) return;

(async () => {
const punctual = new PunctualWrapper({
canvas,
onError: (err) => {
sendToast("destructive", "Punctual error", err.toString());
},
onWarning: (msg) => {
sendToast("warning", "Punctual warning", msg);
},
displaySettings: displaySettings,
});

await punctual.initialize();
setInstance(punctual);

window.parent.punctual = window;
})();

return () => {
instance?.dispose();
};
}, []);

useEffect(() => {
instance?.setDisplaySettings(displaySettings);
}, [displaySettings]);

useEvalHandler(
useCallback(
(msg) => {
if (!instance) return;
instance.tryEval(msg.body);
},
[instance],
),
);

useSettings(
useCallback(
(msg) => {
if (!instance) return;
if (msg.displaySettings) {
setDisplaySettings(msg.displaySettings);
}
},
[instance],
),
);

return (
hasWebGl &&
canvasRef && (
<PunctualCanvas
ref={canvasRef}
fullscreen
displaySettings={displaySettings}
/>
)
);
}
1 change: 1 addition & 0 deletions packages/web/src/routes/session.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ declare global {
hydra: any;
mercury: any;
strudel: any;
punctual: any;
}
}

Expand Down
19 changes: 13 additions & 6 deletions packages/web/src/settings.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
{
"knownTargets": [
"foxdot",
"renardo",
"hydra",
"mercury",
"mercury-web",
"mercury",
"punctual",
"renardo",
"sardine",
"sclang",
"strudel",
Expand All @@ -13,16 +14,22 @@
"defaultTarget": "hydra",
"langByTarget": {
"foxdot": "python",
"renardo": "python",
"hydra": "javascript",
"mercury": "javascript",
"mercury-web": "javascript",
"mercury": "javascript",
"punctual": "tidal",
"renardo": "python",
"sardine": "python",
"sclang": "javascript",
"strudel": "javascript",
"tidal": "tidal"
},
"targetsWithDocumentEvalMode": ["mercury", "mercury-web", "strudel"],
"targetsWithDocumentEvalMode": [
"mercury-web",
"mercury",
"punctual",
"strudel"
],
"panicCodes": {
"tidal": "hush",
"sclang": "CmdPeriod.run",
Expand All @@ -35,7 +42,7 @@
"strudel": "silence",
"sardine": "panic()"
},
"webTargets": ["hydra", "strudel", "mercury-web"],
"webTargets": ["hydra", "mercury-web", "punctual", "strudel"],
"repoUrl": "https://github.com/munshkr/flok",
"changeLogUrl": "https://github.com/munshkr/flok/blob/main/CHANGELOG.md#changelog"
}

0 comments on commit b3dad73

Please sign in to comment.