Official Starters

How To Start A Portal Sketch

  • Scenario 1, cloud editor: write a single copy-paste-friendly `sketch.js` for the base sketch.
  • Cloud base sketch: editor.p5js.org/hobye/sketches/P07GGrfNY
  • Scenario 2, empty local folder on desktop: create a small sketch folder with `index.html`, `style.css`, and `sketch.js`, and load Portal from GitHub-hosted files.
  • Local base sketch: P1/sketches/baseSketch
  • If you need a local multi-file example, copy the `baseSketch` folder and rename it.
  • Use Portal modules with `await loadScript("portal/<module>.js")` instead of rebuilding the feature with unrelated libraries.
  • If Portal already has the feature, stay inside the Portal ecosystem.
Official Starters

What A Model Should Assume

  • If a user references `madshobye.github.io/Portal`, assume they want a Portal-native sketch, not plain p5.js plus custom libraries.
  • Do not refuse because the local folder is empty. In that case, create a `baseSketch`-style folder with `index.html`, `style.css`, and `sketch.js`.
  • Do not refuse because the prompt is only being pasted into an online LLM. In that case, output a single `sketch.js` for the cloud base sketch.
  • Pick the matching Portal module first, then write the sketch around it.
  • Prefer one-file `sketch.js` output unless the user explicitly asks for `index.html` and `style.css` too.
Public API

How Portal Fits Together

  • `index.html` loads p5, Portal base CSS, `portalLoader.js`, and your `sketch.js`.
  • `portalLoader.js` boots the Portal runtime.
  • `sketch.js` loads extra Portal modules with `await loadScript("portal/<module>.js")`.
  • `async setup()` initializes modules.
  • `draw()` combines module outputs through simple state and polling.
Public API

How To Use Portal Correctly

  • Use the hosted `portalLoader.js` or the cloud base sketch.
  • Use Portal modules directly when Portal already has the feature.
  • Use `setupWebcamera(...)` for Portal camera workflows.
  • Use `await loadScript("portal/<module>.js")` instead of writing a custom script loader.
  • Do not swap in `ml5` or raw browser APIs unless the user explicitly asks not to use Portal.
Instructions For LLMs

Write Beginner-Friendly Portal Code

Use p5.js v2+ patterns

Write `async setup()`, use `await`, and in p5.js v2+ load normal assets and modules there instead of relying on `preload()`.

Prefer simple state

Use a few top-level variables, a clear `draw()` loop, and polling instead of deeply nested callbacks.

Use Portal modules directly

Load `portal/speech.js`, `portal/GptClient.js`, `portal/mapper.js`, and other modules with `loadScript(...)` instead of reimplementing loaders.

Starter Pattern

Copy-Paste-Friendly Base

let module; async function setup() { createCanvas(windowWidth, windowHeight); await loadScript("portal/<module>.js"); module = await new SomeModule({}).init(); if (typeof module.start === "function") { await module.start(); } } function draw() { background(0); const result = module?.getLatest?.(); // update sketch state here }
Official Starters

Minimal Portal Starter

This is the default pattern an LLM should generate when asked to make a new Portal sketch. It assumes the standard Portal base sketch or a local sketch folder that already loads `portalLoader.js`.

let video; let handPose; let pinchDown = false; async function setup() { createCanvas(windowWidth, windowHeight); video = await setupWebcamera(true, 640, 480, true); await loadScript("portal/handPose.js"); handPose = await new HandPose({ video, videoIsFlipped: true, backend: "webgl", }).init(); await handPose.start(); } function draw() { background(0); image(video, 0, 0, width, height); const first = handPose?.getHandsInRect?.(0, 0, width, height)?.[0]; // read named landmarks like first.thumb_tip and first.index_finger_tip directly in draw-rect pixels if (pinchDown) { fill(0, 255, 0); noStroke(); ellipse(width * 0.5, height * 0.5, 60, 60); } }
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <meta name="mobile-web-app-capable" content="yes" /> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" /> <title>My Portal Sketch</title> <script src="https://cdn.jsdelivr.net/npm/p5@2.2.0/lib/p5.js"></script> <link rel="stylesheet" type="text/css" href="https://madshobye.github.io/Portal/P1/portalBaseStyle.css" /> <link rel="stylesheet" type="text/css" href="./style.css" /> </head> <body> <main></main> <script src="./sketch.js"></script> <script src="https://madshobye.github.io/Portal/P1/portalLoader.js"></script> </body> </html>

For a standalone local sketch, use the GitHub-hosted `portalLoader.js` and `portalBaseStyle.css` shown above. Inside this repository’s `P1/sketches/<name>/` folders, the local paths are `../../portalLoader.js` and `../../portalBaseStyle.css`. For cloud-editor sketches, you usually only need to replace `sketch.js` in the base sketch.

Public API

Use These Hosted Portal Files

Public API

Use Portal Like A Normal Browser Library

let module; async function setup() { createCanvas(windowWidth, windowHeight); await loadScript("portal/<module>.js"); module = await new SomeModule(...).init(); if (typeof module.start === "function") { await module.start(); } } function draw() { background(0); const result = module?.getLatest?.(); // use result here }
Module Examples

How To Combine Portal Elements

Camera + Tracking

Use `setupWebcamera(...)`, then one tracking module, then render video first and overlays second.

Tracking + UI

Use a tracking module for data and `uiSlim2.js` for thresholds, modes, and debugging.

Speech + GPT

Use `PortalSpeech` for input/output and `GptClient` for interpretation or conversation.

Tracking + GPT

Turn tracked state into text or images, then feed that into `GptClient` for higher-level interpretation.

let video; let tracker; let state = {}; async function setup() { createCanvas(windowWidth, windowHeight); video = await setupWebcamera(true, 640, 480, true); await loadScript("portal/<module>.js"); tracker = await new SomeModule(video).init(); await tracker.start(); } function draw() { background(0); image(video, 0, 0, width, height); state = tracker?.getLatest?.() || {}; // draw overlays // draw UI // trigger sound / GPT / other logic from state }
Module Examples

All Core Modules And Entry Points

Runtime

`portal.js`: `loadScript`, `setupWebcamera`, `storedDecrypt`, `fullScreenToggle`, `getData`, `getP5Instance`

UI

`uiSlim2.js`: `uiButton`, `uiText`, `uiPromptText`, `uiSlider`, `uiToggle`, `uiListStart`, `uiListEnd`, `uiDebug`

GPT And Language

`GptClient`, `PortalSpeech`, `PortalTransformer`

Tracking

`HandPose`, `BodyPose`, `FaceMesh`, `Emotions`, `P5ImageClassifier`, `P5ObjectDetector`, `HandGestureKnn`

Learning

`NeuralLearner`, `KnnLearner`

Devices And IO

`loadSoundFile`, `setupGamepad`, `MultiTouch`, `HeartRateBLE`, `DmxSerial`, `PortalMqtt`

Location And QR

`QrReader`, `createQRCode`, `drawQRCode`, `getLocation`, `getDistanceFromLatLonInKm`, `drawArrow`, `map.js`

Drawing And Mapping

`ProjectionMapper`, `InkDrawing`, `PortalFaceAnimation`, `ChainBrush`, `PortalPaintPath`, `pNoise1D/2D/3D`, `simplexNoise.js`

Module Examples

How To Pick The Right One

  • Need webcam landmarks: `HandPose`, `BodyPose`, `FaceMesh`.
  • Need classification: `P5ImageClassifier`, `P5ObjectDetector`, `KnnLearner`, `NeuralLearner`.
  • Need GPT or language: `GptClient`, `PortalSpeech`, `PortalTransformer`.
  • Need interaction UI: `uiSlim2.js`.
  • Need hardware or external IO: `PortalMqtt`, `DmxSerial`, `HeartRateBLE`, `setupGamepad()`.
  • Need drawing or presentation: `ProjectionMapper`, `InkDrawing`, `PortalFaceAnimation`, `ChainBrush`.
Public API

What Usually Works Best

  • Use `async setup()`.
  • Use `portalLoader.js` as the entry point.
  • Load one Portal module first before combining many.
  • Use one canvas and one `draw()` loop.
  • Prefer polling over nested callbacks.
  • `preload()` is not compatible with p5.js v2.
Internal Details

What To Check First

  • Make sure `index.html` loads the hosted `portalLoader.js` and `portalBaseStyle.css`.
  • Make sure each needed module is loaded with `await loadScript("portal/<module>.js")`.
  • Make sure async modules are initialized with `await new Module(...).init()`.
  • Make sure streaming modules call `start()` when required.
  • Make sure `draw()` reads current state with `getLatest()`, or uses `hasNewResult()` plus `consumeNew()` when the sketch should react only once per update.
Internal Details

Keep Debugging Simple

  • Use `print(...)`, `console.log(...)`, or a short on-canvas status message.
  • Use `uiDebug(...)` if the sketch already uses `uiSlim2.js`.
  • Do not hide errors inside deep promise chains if a beginner needs to understand what failed.
Best Practices

What Usually Works Well

  • One clear idea per sketch.
  • Render first, then draw overlays or detections on top.
  • Use Portal UI helpers for simple controls before building custom DOM.
  • Use structured GPT output when a sketch depends on predictable fields.
  • Stop speech recognition before speech output if self-echo is a risk.
  • Use visible status text or `uiDebug(...)` for errors.
Common Pitfalls

What To Avoid

  • Using `preload()` for normal asset loading in p5.js v2+ instead of `async setup()` with `await`.
  • Mixing many unrelated technologies in one beginner sketch.
  • Adding event-driven complexity when a simple polling loop is enough.
  • Using old p5 sound-loading patterns instead of `portal/SoundFile.js`.
  • Adding sketch-local resize handlers that only duplicate Portal behavior.
Module Overview

Detailed Portal Modules

This section is intended to be copyable reference for LLMs and beginners. Each module card summarizes what it is for, how to load it, and the safest current usage pattern.

Code Recipes

Copy-Paste-Friendly Examples

These are short recipes designed to match the Portal README guidance: async setup, `await`, simple draw-loop polling, and minimal event-driven behavior.

Example Sketches

P1 Examples

Each example has its own folder with `index.html`, `style.css`, and `sketch.js`. Use the live link to run it, and the source link to inspect the code.

Open Sketches Index
Experiments

Related Experiments

These are larger or more exploratory sketches in the repository.