A proof-of-concept demonstrating Figma-style commenting tools that can be injected into any web application without modifying its source code. This simulates how Codesphere could overlay feedback tools onto customer deployments.
βββββββββββββββββββ βββββββββββββββββββ βββββββββββββββββββ
β Browser ββββββΆβ Proxy (:3000) ββββββΆβ Target (:3001) β
β localhost:3000β β Injects script β β Black-box site β
βββββββββββββββββββ ββββββββββ¬βββββββββ βββββββββββββββββββ
β
βΌ
βββββββββββββββββββ
β UI Server(:3002)β
β codesphere- β
β tools.js (IIFE) β
βββββββββββββββββββ
| Server | Port | Purpose |
|---|---|---|
| Proxy | 3000 | Entry point. Fetches HTML from target, injects <script> tag, serves comments API |
| Target App | 3001 | Simulated customer site with zero knowledge of commenting system |
| Commenting UI | 3002 | React overlay bundled as standalone IIFE, mounted in Shadow DOM |
- Zero-Config Injection - Commenting tools appear on any site passing through the proxy
- Shadow DOM Isolation - Overlay CSS is completely isolated from target site styles
- Robust Selector Engine - Generates unique CSS selectors (ID β class β nth-of-type fallback)
- Relative Anchoring - Pins stored as
selector + x/yPercentagefor resize-safe positioning - Draggable Pins - Click and drag any pin to reposition; changes persist to JSON
- Scroll/Resize Sync - Pins follow their target elements via
MutationObserver+ event listeners - Viewport Metadata - Each comment stores the viewport dimensions when created
# Clone the repo
git clone https://github.com/alexvcodesphere/comment-example.git
cd comment-example
# Install all dependencies
cd target-app && npm install && cd ..
cd commenting-ui && npm install && cd ..
cd proxy && npm install && cd ..
# Build the commenting UI bundle
cd commenting-ui && npm run build && cd ..
# Start all three servers (in separate terminals)
cd target-app && npm start # Terminal 1: Port 3001
cd commenting-ui && npm run serve # Terminal 2: Port 3002
cd proxy && npm start # Terminal 3: Port 3000
# Open browser
open http://localhost:3000comments-test/
βββ target-app/ # Port 3001 - Simulated customer site
β βββ index.html # Rich HTML with aggressive CSS
β βββ styles.css # Uses !important to test isolation
β βββ server.js # Express static server
β
βββ commenting-ui/ # Port 3002 - React overlay (IIFE bundle)
β βββ src/
β β βββ main.tsx # Shadow DOM mounting
β β βββ CodesphereOverlay.tsx # Main React component
β β βββ styles.ts # Isolated CSS-in-JS
β β βββ api.ts # REST client
β β βββ types.ts # TypeScript interfaces
β β βββ hooks/
β β β βββ usePinPositions.ts # Scroll/resize/mutation sync
β β βββ utils/
β β βββ getSelector.ts # CSS selector generator
β β βββ positionUtils.ts # Relative anchoring math
β βββ vite.config.ts # IIFE bundle config
β βββ server.js # Static file server for dist/
β
βββ proxy/ # Port 3000 - Injection proxy + API
βββ server.js # HTML injection + /api/comments CRUD
βββ comments.json # JSON file persistence
The proxy intercepts HTML responses and injects:
<script src="http://localhost:3002/codesphere-tools.js"></script>The injected script creates an isolated container:
const container = document.createElement("div");
const shadowRoot = container.attachShadow({ mode: "open" });
// All overlay UI renders inside shadowRootWhen placing a comment, the overlay temporarily hides itself to detect the underlying element:
overlayRoot.style.visibility = "hidden";
const element = document.elementFromPoint(x, y);
overlayRoot.style.visibility = "";Unique selectors are generated with priority:
- ID:
#main-nav - Unique class combo:
.hero-title - nth-of-type:
article.feature-card:nth-of-type(2)
Pins are stored as percentages of the target element:
{
"selector": ".hero-title",
"xPercentage": 66.88,
"yPercentage": 81.25
}| Method | Endpoint | Description |
|---|---|---|
| GET | /api/comments |
Fetch all comments |
| POST | /api/comments |
Create new comment |
| DELETE | /api/comments/:id |
Delete comment |
| PATCH | /api/comments/:id/resolve |
Mark as resolved |
| PATCH | /api/comments/:id/position |
Update position (after drag) |
interface Comment {
id: string;
selector: string; // CSS selector of target element
xPercentage: number; // 0-100, relative to element width
yPercentage: number; // 0-100, relative to element height
content: string;
author: { id; name; avatar };
createdAt: string;
resolved: boolean;
viewport?: { width; height }; // Screen size when comment was made
}- Staging review - Get feedback on deployments before production
- Design QA - Designers can annotate specific UI elements
- Bug reporting - Pin comments to exact problem areas
- Client feedback - Non-technical stakeholders can comment visually
Deploy as 3 separate services with path-based routing:
| Service | Env Variable | Value | Description |
|---|---|---|---|
| Target App | BASE_PATH |
/target |
Path where service is mounted |
| Commenting UI | BASE_PATH |
/commenting-ui |
Path where service is mounted |
| Proxy | TARGET_URL |
https://<workspace>.codesphere.com/target |
Full URL to Target App |
| Proxy | TOOLS_URL |
https://<workspace>.codesphere.com/commenting-ui |
Full URL to Commenting UI |
# CI Pipeline
cd target-app && npm install
# Run Command
cd target-app && node server.js
# Environment Variables
BASE_PATH=/target# CI Pipeline
cd commenting-ui && npm install && npm run build
# Run Command
cd commenting-ui && node server.js
# Environment Variables
BASE_PATH=/commenting-ui# CI Pipeline
cd proxy && npm install
# Run Command
cd proxy && node server.js
# Environment Variables
TARGET_URL=https://77015-3000.2.codesphere.com/target
TOOLS_URL=https://77015-3000.2.codesphere.com/commenting-uiNote: Replace
77015-3000.2.codesphere.comwith your actual Codesphere workspace URL.
MIT