Skip to content

Conversation

max-drake
Copy link
Contributor

Changes the agent's viewport zoom to no longer track the user's zoom 1:1.

The agent's viewport zoom now stays between 75% and 125%, depending on the user's zoom level

Change type

  • bugfix
  • improvement
  • feature
  • api
  • other

@max-drake max-drake requested a review from TodePond October 6, 2025 11:11
@huppy-bot huppy-bot bot added the improvement Product improvement label Oct 6, 2025
Copy link

vercel bot commented Oct 6, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Updated (UTC)
analytics Ready Ready Preview Oct 6, 2025 4:08pm
examples Ready Ready Preview Oct 6, 2025 4:08pm
3 Skipped Deployments
Project Deployment Preview Updated (UTC)
tldraw-docs Ignored Ignored Preview Oct 6, 2025 4:08pm
chat-template Skipped Skipped Oct 6, 2025 4:08pm
workflow-template Skipped Skipped Oct 6, 2025 4:08pm

Copy link

cloudflare-workers-and-pages bot commented Oct 6, 2025

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Updated (UTC)
❌ Deployment failed
View logs
agent-template d606be8 Oct 06 2025, 04:10 PM

Copy link

claude bot commented Oct 6, 2025

🤖 Claude Code Review

Summary

This PR improves the agent viewport zoom behavior by mapping the user's zoom level to a constrained range (75%-125%) instead of tracking it 1:1. This is a sensible UX improvement that should help the agent operate more effectively at various zoom levels.

Code Quality ✅

Good practices observed:

  • Clear method naming (calculatViewportBounds())
  • Comprehensive JSDoc documentation
  • Logical code organization (moving calculation to agent class)

Issues found:

1. Typo in method name (line 723)

calculatViewportBounds() // Missing 'e' in 'calculate'

Should be: calculateViewportBounds()

This typo appears in:

  • templates/agent/client/agent/TldrawAgent.ts:217
  • templates/agent/client/agent/TldrawAgent.ts:723
  • templates/agent/client/components/ChatPanel.tsx:47

2. Box mutation concern (line 742-753)

The scaleBoxFromCenter helper function mutates the input box parameter:

function scaleBoxFromCenter(box: Box, scale: number) {
    // ... mutates box properties directly
    box.x = center.x - newWidth / 2
    box.y = center.y - newHeight / 2
    box.w = newWidth
    box.h = newHeight
    return box
}

This is potentially problematic because:

  • It's unclear if Box.FromCenter() returns a new box or a reference
  • Mutating parameters can lead to unexpected side effects
  • The pattern is inconsistent with functional programming best practices

Recommendation: Create a new Box instead:

function scaleBoxFromCenter(box: Box, scale: number) {
    const { center } = box
    const newWidth = box.w * scale
    const newHeight = box.h * scale
    
    return new Box(
        center.x - newWidth / 2,
        center.y - newHeight / 2,
        newWidth,
        newHeight
    )
}

Logic & Correctness ⚠️

3. Inverted zoom mapping logic (line 733)

const mappedZoom = modulate(editor.getZoomLevel(), [zoomMin, zoomMax], [1.25, 0.75])

The mapping appears counterintuitive:

  • When user zooms IN (closer), zoom level → max, mapped zoom → 0.75 (agent sees LESS)
  • When user zooms OUT (farther), zoom level → min, mapped zoom → 1.25 (agent sees MORE)

Question: Is this intentional? The behavior seems reversed from what you might expect. When the user is zoomed in close, shouldn't the agent also work in a tighter viewport?

If this is intentional (compensating behavior), consider adding a comment explaining the reasoning.

Performance ⚡

4. Recalculation on every prompt (line 217, 47)

The viewport bounds are recalculated on every user prompt. This should be fine for typical usage, but consider:

  • Is caching needed if prompts are sent very frequently?
  • Could this be memoized based on zoom level?

For the current use case, this is likely not a concern, but worth noting for future optimization.

Test Coverage ❌

No tests found for this functionality. While this is a template/example, consider:

  • Unit tests for calculateViewportBounds() with various zoom levels
  • Tests verifying the zoom range mapping (75%-125%)
  • Visual/integration tests for agent behavior at different zoom levels

Security 🔒

No security concerns identified. This is viewport calculation logic with no external inputs.

Overall Assessment

Rating: Good with minor issues

The core logic is sound and the refactoring to move calculation into the agent class is appropriate. The main issues are:

  1. Critical: Typo in method name (easy fix)
  2. Important: Consider reversing zoom mapping or documenting the rationale
  3. Nice-to-have: Avoid box mutation, add tests

Recommendations

  1. Fix the typo: calculatViewportBoundscalculateViewportBounds
  2. Verify the zoom mapping direction is correct (line 733)
  3. Consider immutable box creation in scaleBoxFromCenter
  4. Add a comment explaining why agent zoom moves inversely to user zoom (if intentional)
  5. Consider adding basic unit tests for the calculation logic

Would you like me to create a follow-up commit addressing any of these issues?

Copy link

claude bot commented Oct 6, 2025

🤖 Claude Code Review

Summary

This PR improves the agent's viewport zoom behavior by mapping the user's zoom level to a constrained range (75%-125%) instead of tracking it 1:1. The implementation is clean and well-documented.

Code Quality ✅

Strengths:

  • Clear JSDoc documentation explaining the purpose of calculateViewportBounds()
  • Good separation of concerns - extracted logic into a dedicated method
  • Consistent usage across both call sites (TldrawAgent.ts:218 and ChatPanel.tsx:47)
  • Clean helper function scaleBoxFromCenter nested within the method

Minor Style Observations:

  • The nested scaleBoxFromCenter function follows a reasonable pattern for local utility functions
  • Proper use of the modulate utility function from the utils package

Implementation Review ✅

The zoom mapping logic is sound:

const mappedZoom = modulate(editor.getZoomLevel(), [zoomMin, zoomMax], [1.25, 0.75])

This maps the user's zoom from their full available range to [1.25, 0.75], meaning:

  • When user is at min zoom (zoomed out), agent sees 1.25x scale (larger viewport)
  • When user is at max zoom (zoomed in), agent sees 0.75x scale (smaller viewport)

This inverse relationship makes sense: when the user zooms in to see details, the agent should have a tighter viewport to focus on relevant content.

Potential Considerations

1. Edge Cases ⚠️

The code assumes zoomSteps array is non-empty. Consider what happens if:

const zoomSteps = editor.getCameraOptions().zoomSteps
const zoomMin = zoomSteps[0]  // Could be undefined if array is empty
const zoomMax = zoomSteps[zoomSteps.length - 1]

Recommendation: Add a guard or assertion, though this is likely safe given the tldraw editor always has zoom steps defined.

2. Magic Numbers 🔍

The values [1.25, 0.75] are hardcoded. While the PR description mentions "75% and 125%", these might benefit from:

  • Named constants explaining their purpose
  • Comments explaining why these specific bounds were chosen
  • Configuration options if these need to be tunable

Example:

// Agent viewport should range from 75% to 125% of screen size
// This ensures the agent has adequate context without becoming
// disoriented at extreme zoom levels
const AGENT_VIEWPORT_SCALE_MIN = 0.75
const AGENT_VIEWPORT_SCALE_MAX = 1.25
const mappedZoom = modulate(editor.getZoomLevel(), [zoomMin, zoomMax], 
  [AGENT_VIEWPORT_SCALE_MAX, AGENT_VIEWPORT_SCALE_MIN])

3. Test Coverage 🧪

There are no tests in the agent template. Consider adding tests for:

  • calculateViewportBounds() with various zoom levels
  • Boundary conditions (min/max zoom)
  • Verification that agent viewport stays within expected bounds

4. Performance Consideration ✅

The method creates new Box instances on each call. This is fine for user interactions but worth noting if called frequently in loops or reactive contexts.

Security ✅

No security concerns identified. The code operates on geometric calculations without user input sanitization needs.

Best Practices ✅

  • Follows tldraw conventions for method naming and structure
  • Properly imports required utilities (modulate, Box)
  • Maintains editor pattern usage

Verdict

This is a solid improvement with clean implementation. The main suggestions are:

  1. Consider extracting magic numbers to named constants
  2. Add inline comment explaining the inverse zoom relationship
  3. Consider test coverage for future maintainability

Overall: Approved with minor suggestions

Copy link

claude bot commented Oct 6, 2025

🤖 Claude Code Review

Summary

This PR appears to be a massive initial import of the entire tldraw codebase (~5000+ files). Given the scope, this review focuses on high-level architectural observations and key areas to verify.

Repository Structure ✅

The monorepo structure follows solid engineering practices:

  • Clear separation of concerns: apps/, packages/, templates/
  • Comprehensive documentation: CLAUDE.md, CONTEXT.md files throughout
  • Modern tooling: Yarn workspaces, Vite, TypeScript, Playwright

Key Observations

Strengths 👍

  1. Excellent documentation structure

    • CLAUDE.md provides clear AI agent guidance
    • CONTEXT.md files distributed throughout for contextual understanding
    • Comprehensive README and contribution guidelines
  2. Strong DevOps/CI setup

    • Multiple GitHub Actions workflows for different deployment scenarios
    • Proper separation of staging/production environments
    • E2E testing infrastructure with Playwright
  3. Security practices

    • Security policy (SECURITY.md)
    • CLA and contribution guidelines
    • Proper gitignore patterns
  4. Type safety

    • TypeScript throughout
    • API Extractor for public API validation
    • Workspace references for incremental compilation

Recommendations 🔍

1. Review Secret Management

Since this is a full repository import, verify that no secrets were accidentally committed:

  • Check .env files are in .gitignore
  • Scan for API keys, tokens, credentials in configuration files
  • Review wrangler.toml files for sensitive data

2. Dependency Audit

With this many packages, recommend running:

yarn audit

To identify any known vulnerabilities in dependencies.

3. License Compliance

Verify all third-party dependencies are compatible with your MIT license:

  • Check node_modules licenses
  • Review yarn patches for license compliance

4. Build System Verification

Test the complete build pipeline:

yarn install
yarn typecheck
yarn lint
yarn test run

5. Code Quality Checks

  • No obvious anti-patterns detected in the structure
  • Consider adding:
    • Pre-commit hooks for linting (Husky is configured ✅)
    • Commit message conventions
    • Branch protection rules

Architecture Highlights 🏗️

Reactive State Management

  • Uses custom @tldraw/state library for signals
  • Good separation of concerns with ShapeUtil and StateNode patterns

Multiplayer Architecture

  • Proper separation of sync logic in @tldraw/sync
  • Cloudflare Workers for backend (bemo-worker, sync-worker)

Testing Strategy

  • Unit tests with Vitest
  • E2E tests with Playwright
  • Good test infrastructure setup

Potential Issues ⚠️

  1. Bundle Size: With this many packages, monitor bundle sizes carefully
  2. Monorepo Complexity: Consider documenting dependency graph
  3. Translation Files: 60+ locale files could lead to maintenance burden

Security Considerations 🔒

  1. Cloudflare Workers: Review wrangler.toml files for production secrets
  2. API Routes: Ensure proper authentication/authorization in dotcom client
  3. Asset Upload: Verify asset-upload-worker has proper file validation
  4. CORS: Check CORS policies in worker configurations

Performance Considerations ⚡

  1. Lazy Loading: Consider code splitting for the large app bundle
  2. Asset Optimization: Verify images/fonts are properly optimized
  3. Translation Loading: Consider lazy loading locale files

Test Coverage 🧪

Given the size of the codebase, recommend:

  • Setting up code coverage reporting
  • Establishing coverage thresholds
  • Documenting critical paths that need testing

Next Steps

  1. ✅ Run full test suite
  2. ✅ Verify all builds pass
  3. ✅ Review deployment configurations
  4. ✅ Scan for secrets/credentials
  5. ✅ Run security audit on dependencies
  6. ✅ Verify license compliance

Conclusion

This is a well-structured, professionally organized codebase with excellent documentation and tooling. For an initial import of this scale, the architecture and organization are solid. Primary recommendations focus on verification steps (secrets, dependencies, licenses) rather than code quality concerns.

Approval Status: Pending verification of the recommended security and dependency audits.

Copy link

claude bot commented Oct 6, 2025

🤖 Claude Code Review

Summary

This PR improves the agent viewport zoom behavior by decoupling the agent's viewport zoom from the user's zoom level. The agent's zoom is now clamped between 75% and 125% (0.67-1.25 in code) to provide a more consistent working area for AI agents.

Code Quality ✅

Strengths:

  • Clean implementation with well-documented methods
  • Good separation of concerns with the new calculateViewportBounds() method
  • Consistent variable naming improvements (e.g., contextBoundsagentViewportBoundsBox)
  • Helpful inline comments explaining the zoom mapping logic

Issues Found:

1. 🔴 Debug Console.log Left in Production Code

Location: templates/agent/worker/do/AgentService.ts:61

console.log('messages', JSON.stringify(messages, null, 2))

This debug statement should be removed before merging to production. It could:

  • Create noise in production logs
  • Potentially log sensitive data
  • Impact performance with large message payloads

Recommendation: Remove this line or use a proper logging framework with configurable log levels.

2. 🟡 Typo Fix in buildSystemPrompt.ts

Location: templates/agent/worker/prompt/buildSystemPrompt.ts:14-21

Good catch fixing the typo (propmtUtilspromptUtils), but this appears to be an incidental cleanup rather than part of the main feature. Consider noting typo fixes in the PR description for clarity.

3. 🟡 Magic Numbers in Zoom Clamping

Location: templates/agent/client/agent/TldrawAgent.ts:735

const clampedZoom = clamp(editor.getZoomLevel(), 0.67, 1.25)

The values 0.67 and 1.25 are hardcoded. The PR description mentions "75% and 125%", but:

  • 0.67 ≈ 67%, not 75% (1/1.5 ≈ 0.67 might be intentional for inverse scaling)
  • Consider extracting these as named constants for maintainability

Recommendation:

const MIN_AGENT_ZOOM = 0.67 // Equivalent to 150% user zoom (1/1.5)
const MAX_AGENT_ZOOM = 1.25 // Equivalent to 80% user zoom (1/0.8)
const clampedZoom = clamp(editor.getZoomLevel(), MIN_AGENT_ZOOM, MAX_AGENT_ZOOM)

Or add a comment explaining the inverse relationship if that's the intent.

Architecture & Design ✅

Positive:

  • The calculateViewportBounds() method is well-structured and reusable
  • Nested helper function scaleBoxFromCenter() is clean and focused
  • Changes are localized to the agent template without affecting core SDK

Suggestion:
Consider making scaleBoxFromCenter a utility function in the Box class or a shared utility if this pattern is used elsewhere in the codebase.

Performance Considerations ✅

  • The viewport calculation is lightweight (basic math operations)
  • Called only when needed (on prompt requests)
  • No performance concerns identified

Testing 🟡

Missing:

  • No test coverage for the new calculateViewportBounds() method
  • No tests validating zoom clamping behavior
  • No tests for edge cases (very small/large zoom levels)

Recommendation:
Add unit tests for:

  1. Zoom clamping at boundaries (< 0.67, > 1.25)
  2. Center point preservation
  3. Bounds calculation accuracy

Security ✅

No security concerns identified. The changes are isolated to viewport calculations and don't involve user input validation or data persistence.

Documentation 📝

Good:

  • JSDoc comment on calculateViewportBounds() is clear
  • System prompt update guides the agent properly
  • Variable naming improvements enhance readability

Could Improve:

  • The PR description states "75% and 125%" but the code uses 0.67 and 1.25. Clarify this discrepancy (inverse scaling vs. absolute zoom levels).

Summary of Recommendations

Must Fix:

  • 🔴 Remove console.log from AgentService.ts:61

Should Consider:

  • 🟡 Add named constants for zoom thresholds with explanatory comments
  • 🟡 Add unit tests for viewport bounds calculation
  • 🟡 Clarify zoom percentage documentation (75% vs. 67%)

Nice to Have:

  • Consider extracting scaleBoxFromCenter as a reusable utility

Overall Assessment

This is a well-implemented improvement that addresses a real UX issue with agent viewport behavior. The code is clean and maintainable, with only minor issues to address before merging. The debug console.log is the only blocking issue.

Approval Status: Approve pending removal of console.log statement.

@@ -153,7 +153,7 @@ Refer to the JSON schema for the full list of available events, their properties
- You will be provided with list of shapes that are outside of your viewport.
- You can use the \`setMyView\` action to change your viewport to navigate to other areas of the canvas if needed. This will provide you with an updated view of the canvas. You can also use this to functionally zoom in or out.
- Never send any events after you have used the \`setMyView\` action. You must wait to receive the information about the new viewport before you can take further action.
- Always make sure that any shapes you create or modify are within your viewport.
- Always make sure that any shapes you create or modify are within your viewport. Move your viewport to ensure that the shapes are within your view.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this PR still being worked on? We should remove this first sentence — We don't want it to stay inside its viewport.

@TodePond
Copy link
Collaborator

fixed in a separate PR

@TodePond TodePond closed this Oct 14, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

improvement Product improvement

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants