Conversation
Move the famous-sidecar load (famous_meta.json + famous_xrefs.json) out of App.tsx into a dedicated hook. Pure relocation, no behavior change. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
useFamousMeta returns readonly FamousMetaEntry[]; CommandPalette's entries prop accepts readonly. Aligns with useFocusUrlSync and EngineHandle.selectByAlias which already use readonly. No mutation in CommandPalette to relax for. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Move the lazy palette-alias load out of App.tsx. The pure buildAliasIndex helper gets full unit coverage in node; the React glue is a thin useEffect wrapper. No behavior change. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Add a comment on the useEffect dep array explaining why engineHandleRef is listed (stable ref, linter satisfaction). Re-export AliasIndexEntry alongside UseAliasIndexReturn so callers don't need a second import path, matching the useFocusUrlSync re-export pattern. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Six-task plan to extract App.tsx (~909 lines) into 5 focused hooks under src/hooks/. Each task is self-contained: useFamousMeta, useAliasIndex, useKeyboardShortcuts, useEngineSettings, useEngine, plus a final cleanup pass. Tasks 1 and 2 already landed on this branch. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Move the global keydown listener (Esc / f / h / l / Cmd+K / /) out of App.tsx into a dedicated hook. Pure relocation, no behavior change. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
An inline arrow `() => setPaletteOpen(true)` at the call site was a fresh identity each render and caused the hook's effect to re-bind the window keydown listener on every App render. Take the React setter directly — it's a stable reference, so the effect re-binds only when `selected` or `paletteOpen` actually change. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The original App.tsx keydown effect only guarded INPUT / TEXTAREA / contenteditable. A focused <select> still receives letter keystrokes on most platforms (jump-to-option), so hitting `h` while the BiasMode or ToneMapCurve select was focused would unexpectedly yank the camera home. Add SELECT to the guard. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Move ~17 settings useStates and their EngineCallbacks echo slice into a single hook. App.tsx now spreads settingsCallbacks into createEngine. The three App-owned setters (filaments enabled / intensity, exposure) are returned from the hook for SettingsPanel onChange wiring. Pure relocation, no behavior change. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Move createEngine startup, canvasRef, handleRef, and engine-driven state (status, hovered, selected, focused, scale, fps, sourceCounts, loadProgress, currentTier) out of App.tsx into a dedicated hook. useEngine accepts extraCallbacks so useEngineSettings can layer in its echo callbacks. Pure relocation, no behavior change. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The SpaceMouse panel section was gated off long ago; its connected / sensitivity useStates were write-only. isWebHIDSupported import was unused. initialMobile / initialPanelsOpen were re-evaluated every render despite being mount-time constants — wrap initialMobile in a useState lazy initializer so the SSR guard + viewport read run once. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
skymap | f7591a1 | Commit Preview URL Branch Preview URL |
May 06 2026, 11:20 AM |
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
skymap | 3d05c30 | Commit Preview URL Branch Preview URL |
May 06 2026, 11:23 AM |
Address Important + Minor items from the final whole-implementation review of the hook refactor: - Drop the dead `pendingTarget` destructure from useFocusUrlSync (the hook still runs for its side effects; pendingTarget is reserved for a future tier-mismatch banner that doesn't exist yet). - Reconcile the exposure-handler comment with reality: the optimistic setExposure(value) IS needed for snappy slider tracking; explain why this differs from the discrete tone-curve / bias-mode controls. - Rewrite the App.tsx module-level docblock to describe the hook- delegation architecture instead of the pre-refactor structure. - Extend the useEngine effect's lint-suppression comment to name `currentTier` alongside `extraCallbacks` so a future reader doesn't have to wonder why both are intentionally captured-not-listed. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Extract the 909-line
src/components/App/App.tsxinto 5 focused custom hooks undersrc/hooks/, leaving App.tsx as a 455-line wiring layer. Pure refactor — no user-visible behavior change.Hooks created
useFamousMetaloadFamousSidecars()once at mount; returns{ famousMeta, famousXrefs }useAliasIndex(+ purebuildAliasIndexhelper, 5 unit tests)useKeyboardShortcuts/); takessetPaletteOpendirectly so the effect doesn't rebind every render. Form-field guard now includes SELECTuseEngineSettingsuseEnginePlus dead-code cleanup: removed write-only SpaceMouse useStates, unused
isWebHIDSupportedimport, and hoistedinitialMobileto auseStatelazy initializer so the SSR guard runs once.App.tsx: 909 → 455 lines (~50% reduction).
Test count: 826 → 831 (+5 from
buildAliasIndexunit tests).Plan + workflow
Implementation plan:
docs/superpowers/plans/2026-05-06-app-tsx-hook-refactor.md. Each task ran through implement → spec compliance review → code quality review (when meaningful) → fix any issues. Final whole-implementation review is in progress; any flagged issues will land as follow-up commits on this branch.Test plan
npm run typecheckcleannpm test— 831/831 passffocuses;hhome; SettingsPanel sliders apply (point size, brightness, exposure, tone curve); deep-link#focus=m81lands on M81; tier swap works; survey toggles workFollow-up (separate PR)
Unrelated bug observed during testing:
fallbackOrientation.ts:33throws "Cannot mix BigInt and other types" on hover for some galaxies — likely a non-BigIntobjIDslipping through from a synthetic or misconstructed cloud. Defensive coercion athashSeedentry will fix it. Tracking separately.🤖 Generated with Claude Code