diff --git a/src/operations/scaffold.js b/src/operations/scaffold.js index ce59845..967289a 100644 --- a/src/operations/scaffold.js +++ b/src/operations/scaffold.js @@ -16,7 +16,7 @@ import * as display from '../ui/display.js'; import * as prompts from '../ui/prompts.js'; // Business utilities -import { copyTemplateFiles, validateProjectName, directoryExists, validateMode, validateVersion, validateLanguage, validateP5Mode, getTemplateName, generateProjectName, isRemoteTemplateSpec } from '../utils.js'; +import { copyTemplateFiles, validateProjectName, directoryExists, validateMode, validateVersion, validateLanguage, validateP5Mode, getTemplateDirName, generateProjectName, isRemoteTemplateSpec } from '../utils.js'; import { fetchVersions, downloadP5Files, downloadTypeDefinitions } from '../version.js'; import { injectP5Script } from '../htmlManager.js'; import { createConfig } from '../config.js'; @@ -312,7 +312,7 @@ export async function scaffold(args) { templateDir = 'minimal-global-js'; } else { // Standard and custom use template based on language and mode - templateDir = getTemplateName(selectedLanguage, selectedP5Mode); + templateDir = getTemplateDirName(selectedLanguage, selectedP5Mode); } const templatePath = path.join(__dirname, '..', '..', 'templates', templateDir); @@ -338,7 +338,7 @@ export async function scaffold(args) { } // If local mode, create lib directory and download p5.js files - if (selectedMode === 'local') { + if (selectedMode === 'local' && selectedLanguage !== "typescript") { const libPath = path.join(targetPath, 'lib'); await fs.mkdir(libPath, { recursive: true }); try { @@ -359,19 +359,20 @@ export async function scaffold(args) { process.exit(1); } } - - // Inject p5.js script tag into index.html - const indexPath = path.join(targetPath, 'index.html'); - const htmlContent = await fs.readFile(indexPath, 'utf-8'); - const updatedHtml = injectP5Script(htmlContent, selectedVersion, selectedMode); - await fs.writeFile(indexPath, updatedHtml, 'utf-8'); + if (selectedLanguage !== "typescript"){ + // Inject p5.js script tag into index.html + const indexPath = path.join(targetPath, 'index.html'); + const htmlContent = await fs.readFile(indexPath, 'utf-8'); + const updatedHtml = injectP5Script(htmlContent, selectedVersion, selectedMode); + await fs.writeFile(indexPath, updatedHtml, 'utf-8'); + } // Download TypeScript definitions (skip for basic setup) let typeDefsVersion = null; if (setupType === 'basic') { // Basic setup never includes type definitions display.info('info.skipTypesBasic'); - } else if (args.types !== false) { + } else if (args.types !== false && selectedLanguage !== "typescript") { const typesPath = path.join(targetPath, 'types'); await fs.mkdir(typesPath, { recursive: true }); try { diff --git a/src/utils.js b/src/utils.js index 5446599..d899f8f 100644 --- a/src/utils.js +++ b/src/utils.js @@ -268,11 +268,15 @@ export function validateP5Mode(mode) { /** * Determines template directory name from language and mode - * @param {string} language - 'javascript' or 'typescript' - * @param {string} mode - 'global' or 'instance' + * @param {"javascript" | "typescript"} language + * @param {"global" | "instance"} mode * @returns {string} Template directory name (e.g., 'basic-global-js') */ -export function getTemplateName(language, mode) { +export function getTemplateDirName(language, mode) { + //For TS we use the same template for global and instance modes. + if(language==="typescript" && mode==="instance"){ + mode = "global"; + } const langSuffix = language === 'typescript' ? 'ts' : 'js'; return `basic-${mode}-${langSuffix}`; } diff --git a/templates/basic-global-ts/.gitignore b/templates/basic-global-ts/.gitignore new file mode 100644 index 0000000..a547bf3 --- /dev/null +++ b/templates/basic-global-ts/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/templates/basic-global-ts/README.md b/templates/basic-global-ts/README.md new file mode 100644 index 0000000..aed491e --- /dev/null +++ b/templates/basic-global-ts/README.md @@ -0,0 +1,36 @@ +# p5.js v2.x TypeScript project + +## Prerequisites + +- [Node.js](https://nodejs.org/) + +## Getting Started + +### Install and run + +To install dependencies and start vite dev server + +```bash +npm i +npm run dev +``` + +### Choose global-mode or instance-mode p5.js + +Two sketches are provided in src, one for each mode. + +If you're not sure, use global mode. + +Delete whichever of the two you don't need, + +Ensure index.html is pointing at the right one. + +### (optional) Type-check all your files + +VSCode will type-check the files you currently have open. + +To type-check _all_ your files, run: + +```bash +npm run type-check +``` diff --git a/templates/basic-global-ts/index.html b/templates/basic-global-ts/index.html index 7697ff4..d1b9dd0 100644 --- a/templates/basic-global-ts/index.html +++ b/templates/basic-global-ts/index.html @@ -1,13 +1,14 @@ - - - - p5.js TypeScript - - - - - - + + + + My p5.js v2 TypeScript Sketch + + + + + + + diff --git a/templates/basic-global-ts/package.json b/templates/basic-global-ts/package.json new file mode 100644 index 0000000..fc4f0e4 --- /dev/null +++ b/templates/basic-global-ts/package.json @@ -0,0 +1,18 @@ +{ + "name": "p5-v2-typescript-sketch", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc && vite build", + "preview": "vite preview", + "type-check": "tsc --noEmit", + "type-check:watch": "tsc --noEmit --watch" + }, + "devDependencies": { + "p5": "^2.1.1", + "typescript": "~5.9.3", + "vite": "^7.2.4" + } +} diff --git a/templates/basic-global-ts/sketch.ts b/templates/basic-global-ts/sketch.ts deleted file mode 100644 index 2cade99..0000000 --- a/templates/basic-global-ts/sketch.ts +++ /dev/null @@ -1,9 +0,0 @@ -function setup(): void { - createCanvas(400, 400); - background(220); -} - -function draw(): void { - // Draw a simple circle that follows the mouse - ellipse(mouseX, mouseY, 50, 50); -} diff --git a/templates/basic-global-ts/src/sketchGlobalMode.ts b/templates/basic-global-ts/src/sketchGlobalMode.ts new file mode 100644 index 0000000..e2317bc --- /dev/null +++ b/templates/basic-global-ts/src/sketchGlobalMode.ts @@ -0,0 +1,26 @@ +import "p5/global"; + +//needed for p5.Vector, p5.Geometry, etc. +//import p5 from "p5"; + +window.setup = function setup(): void { + createCanvas(400, 400); + background(220); +}; + +window.draw = function draw(): void { + line(pmouseX, pmouseY, mouseX, mouseY); +}; + +window.mousePressed = function mousePressed() { + fill(randomColour()); + circle(mouseX, mouseY, random(10, 30)); +}; + +function randomColour(): p5.Color { + push(); + colorMode(HSB); + const generatedColour = color(random(360), 70, 100); + pop(); + return generatedColour; +} diff --git a/templates/basic-global-ts/src/sketchInstanceMode.ts b/templates/basic-global-ts/src/sketchInstanceMode.ts new file mode 100644 index 0000000..2422faf --- /dev/null +++ b/templates/basic-global-ts/src/sketchInstanceMode.ts @@ -0,0 +1,27 @@ +import p5 from "p5"; + +function sketch(p: p5) { + p.setup = function setup(): void { + p.createCanvas(400, 400); + p.background("linen"); + }; + + p.draw = function draw(): void { + p.line(p.mouseX, p.mouseY, p.pmouseX, p.pmouseY); + }; + + p.mousePressed = function mousePressed() { + p.fill(randomColour()); + p.circle(p.mouseX, p.mouseY, 20); + }; + + function randomColour(): p5.Color { + p.push(); + p.colorMode(p.HSB); + const generatedColour = p.color(p.random(360), 70, 100); + p.pop(); + return generatedColour; + } +} + +new p5(sketch); diff --git a/templates/basic-global-ts/src/style.css b/templates/basic-global-ts/src/style.css new file mode 100644 index 0000000..be4b9d3 --- /dev/null +++ b/templates/basic-global-ts/src/style.css @@ -0,0 +1,5 @@ +html, +body { + margin: 0; + padding: 0; +} diff --git a/templates/basic-global-ts/style.css b/templates/basic-global-ts/style.css deleted file mode 100644 index f9dddd6..0000000 --- a/templates/basic-global-ts/style.css +++ /dev/null @@ -1,13 +0,0 @@ -body { - margin: 0; - padding: 0; - display: flex; - justify-content: center; - align-items: center; - min-height: 100vh; - background-color: #f0f0f0; -} - -canvas { - box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); -} diff --git a/templates/basic-global-ts/tsconfig.json b/templates/basic-global-ts/tsconfig.json index d4430c1..74edca6 100644 --- a/templates/basic-global-ts/tsconfig.json +++ b/templates/basic-global-ts/tsconfig.json @@ -1,14 +1,26 @@ { - "compilerOptions": { - "target": "ES6", - "module": "ESNext", - "lib": ["ES6", "DOM"], - "strict": true, - "skipLibCheck": true, - "noEmit": true - }, - "include": [ - "*.ts", - "types/*.d.ts" - ] + "compilerOptions": { + "target": "ES2022", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "types": ["vite/client"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] }