Skip to content

Commit 521cbd7

Browse files
committed
refactor: delete orphan declarations flagged by fallow
After fallow's auto-fix de-exports unused symbols, oxlint surfaces them as no-unused-vars. This PR deletes those orphan declarations outright. Biggest cleanup: studio/src/icons/SystemIcons.tsx shrinks from 132 to 57 lines — 33 unused icon wrappers and their phosphor-icon imports deleted. Other deletions across 14 more files covering paired getter/setters, helper functions, dead env constants, internal components with no callers, and cascading unused imports. Cascade-causing files held back for follow-up PRs: renderOrchestrator barrel of captureCost re-exports, telemetry/portUtils/remote barrels, Button.tsx + ui/index.ts (would orphan whole file), studioMotion type re-exports. Test plan: typecheck clean across 8 packages, oxlint + oxfmt clean, fallow audit exit 0 (remaining findings inherited), cli + studio vitest suites pass.
1 parent 1e5397d commit 521cbd7

16 files changed

Lines changed: 9 additions & 453 deletions

File tree

packages/aws-lambda/src/s3Transport.ts

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,10 @@ import {
2222
createWriteStream,
2323
existsSync,
2424
mkdirSync,
25-
readdirSync,
2625
rmSync,
2726
statSync,
2827
} from "node:fs";
29-
import { dirname, join } from "node:path";
28+
import { dirname } from "node:path";
3029
import { pipeline } from "node:stream/promises";
3130
import { GetObjectCommand, PutObjectCommand, type S3Client } from "@aws-sdk/client-s3";
3231
import * as tar from "tar";
@@ -138,19 +137,3 @@ export async function untarDirectory(tarballPath: string, destDir: string): Prom
138137
mkdirSync(destDir, { recursive: true });
139138
await tar.extract({ file: tarballPath, cwd: destDir });
140139
}
141-
142-
/** List all regular files under a directory, sorted, returned as absolute paths. */
143-
export function listFilesInDirectory(dir: string): string[] {
144-
const out: string[] = [];
145-
function walk(d: string): void {
146-
for (const entry of readdirSync(d, { withFileTypes: true }).sort((a, b) =>
147-
a.name < b.name ? -1 : a.name > b.name ? 1 : 0,
148-
)) {
149-
const full = join(d, entry.name);
150-
if (entry.isDirectory()) walk(full);
151-
else if (entry.isFile()) out.push(full);
152-
}
153-
}
154-
walk(dir);
155-
return out;
156-
}

packages/cli/src/browser/manager.ts

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,6 @@ const CACHE_DIR = join(homedir(), ".cache", "hyperframes", "chrome");
1313
// too or it silently picks system Chrome over a perfectly good headless-shell.
1414
const PUPPETEER_CACHE_DIR = join(homedir(), ".cache", "puppeteer", "chrome-headless-shell");
1515

16-
/** Override browser path via --browser-path flag. Takes priority over env var. */
17-
let _browserPathOverride: string | undefined;
18-
export function setBrowserPath(path: string): void {
19-
_browserPathOverride = path;
20-
}
21-
2216
export type BrowserSource = "env" | "cache" | "system" | "download";
2317

2418
export interface BrowserResult {
@@ -61,10 +55,6 @@ function whichBinary(name: string): string | undefined {
6155
}
6256

6357
function findFromEnv(): BrowserResult | undefined {
64-
// --browser-path flag takes priority
65-
if (_browserPathOverride && existsSync(_browserPathOverride)) {
66-
return { executablePath: _browserPathOverride, source: "env" };
67-
}
6858
const envPath = process.env["HYPERFRAMES_BROWSER_PATH"];
6959
if (envPath && existsSync(envPath)) {
7060
return { executablePath: envPath, source: "env" };

packages/cli/src/capture/assetCataloger.ts

Lines changed: 0 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -288,76 +288,3 @@ function getWidthParam(url: string): number {
288288
return 0;
289289
}
290290
}
291-
292-
/**
293-
* Format cataloged assets as markdown for the DESIGN.md Assets section.
294-
* Matches Aura.build's format: grouped by type, named from file paths.
295-
*/
296-
export function formatAssetCatalog(assets: CatalogedAsset[]): string {
297-
if (assets.length === 0) return "No assets detected.\n";
298-
299-
// Group by type
300-
const groups: Record<string, CatalogedAsset[]> = {};
301-
for (const a of assets) {
302-
const group = a.type;
303-
if (!groups[group]) groups[group] = [];
304-
groups[group]!.push(a);
305-
}
306-
307-
const lines: string[] = [];
308-
309-
// Output in order: Fonts, Images, Videos, Icons, Background, Other
310-
const order: CatalogedAsset["type"][] = ["Font", "Image", "Video", "Icon", "Background", "Other"];
311-
for (const type of order) {
312-
const group = groups[type];
313-
if (!group || group.length === 0) continue;
314-
315-
const sectionName =
316-
type === "Font"
317-
? "Fonts"
318-
: type === "Image"
319-
? "Images"
320-
: type === "Video"
321-
? "Videos"
322-
: type === "Icon"
323-
? "Icons"
324-
: type === "Background"
325-
? "Backgrounds"
326-
: "Other";
327-
lines.push(`### ${sectionName}`);
328-
329-
for (const a of group) {
330-
const name = a.notes || deriveAssetName(a.url);
331-
const contexts = a.contexts.join(", ");
332-
lines.push(`- **${name}**: ${a.url} — contexts: ${contexts}`);
333-
}
334-
lines.push("");
335-
}
336-
337-
return lines.join("\n");
338-
}
339-
340-
/**
341-
* Derive a human-readable name from a URL's file path.
342-
* E.g., "ConnectBentoBackground.jpg" → "Connect Bento Background"
343-
*/
344-
function deriveAssetName(url: string): string {
345-
try {
346-
const u = new URL(url);
347-
const path = u.pathname;
348-
// Get filename without extension
349-
const filename = path.split("/").pop() || "";
350-
const nameWithoutExt = filename.replace(/\.[^.]+$/, "");
351-
// Remove hash suffixes (e.g., "Sohne.cb178166" → "Sohne")
352-
const cleaned = nameWithoutExt.replace(/\.[a-f0-9]{6,}$/, "");
353-
// Convert camelCase/PascalCase to spaces
354-
const spaced = cleaned
355-
.replace(/([a-z])([A-Z])/g, "$1 $2")
356-
.replace(/[-_]/g, " ")
357-
.replace(/\s+/g, " ")
358-
.trim();
359-
return spaced || filename;
360-
} catch {
361-
return "Asset";
362-
}
363-
}

packages/core/src/parsers/htmlParser.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import type {
1010
StageZoomKeyframe,
1111
CompositionVariable,
1212
} from "../core.types";
13-
import { CANVAS_DIMENSIONS } from "../core.types";
1413
import {
1514
parseGsapScript,
1615
validateCompositionGsap,
@@ -902,5 +901,3 @@ function extractGsapScript(doc: Document): string | null {
902901
}
903902
return null;
904903
}
905-
906-
export { CANVAS_DIMENSIONS };

packages/engine/src/services/hdrCapture.ts

Lines changed: 0 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -158,46 +158,6 @@ export async function initHdrReadback(page: Page, width: number, height: number)
158158

159159
// ── HDR frame conversion ──────────────────────────────────────────────────────
160160

161-
/**
162-
* Convert raw rgba64le pixels (from FFmpeg) to a base64 string for FFmpeg encoding.
163-
*
164-
* For HLG sources: the pixel values are already HLG-encoded. We pass them through
165-
* as-is (normalized to 16-bit) and tag the output as HLG. No OETF conversion needed —
166-
* the HLG signal values ARE the correct encoding. Converting to linear and back to
167-
* PQ produces worse results because every viewer's PQ→display tone-mapping differs
168-
* from its HLG→display tone-mapping.
169-
*
170-
* The WebGPU round-trip is skipped for pass-through — the pixels go directly from
171-
* FFmpeg extraction to FFmpeg encoding. WebGPU is only needed when transforms
172-
* (scale, rotate, opacity from GSAP) must be applied to the HDR pixels.
173-
*/
174-
export function convertHdrFrameToRgb48le(
175-
rawRgba64le: Buffer,
176-
width: number,
177-
height: number,
178-
): Buffer {
179-
const input = new Uint16Array(
180-
rawRgba64le.buffer,
181-
rawRgba64le.byteOffset,
182-
rawRgba64le.byteLength / 2,
183-
);
184-
185-
// Convert RGBA → RGB (drop alpha) for rgb48le output
186-
const output = Buffer.alloc(width * height * 6);
187-
188-
for (let y = 0; y < height; y++) {
189-
for (let x = 0; x < width; x++) {
190-
const srcIdx = (y * width + x) * 4;
191-
const dstIdx = (y * width + x) * 6;
192-
output.writeUInt16LE(input[srcIdx] ?? 0, dstIdx);
193-
output.writeUInt16LE(input[srcIdx + 1] ?? 0, dstIdx + 2);
194-
output.writeUInt16LE(input[srcIdx + 2] ?? 0, dstIdx + 4);
195-
}
196-
}
197-
198-
return output;
199-
}
200-
201161
// ── Frame upload + readback ───────────────────────────────────────────────────
202162

203163
/**

packages/shader-transitions/src/webgl.ts

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -147,16 +147,6 @@ export function createTexture(gl: WebGLRenderingContext): WebGLTexture {
147147
return tex;
148148
}
149149

150-
export function uploadTexture(
151-
gl: WebGLRenderingContext,
152-
tex: WebGLTexture,
153-
canvas: HTMLCanvasElement,
154-
): void {
155-
uploadTextureSource(gl, tex, canvas);
156-
canvas.width = 0;
157-
canvas.height = 0;
158-
}
159-
160150
export function uploadTextureSource(
161151
gl: WebGLRenderingContext,
162152
tex: WebGLTexture,
Lines changed: 0 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,5 @@
1-
import { memo } from "react";
21
import type { DomEditLayerItem } from "./domEditing";
32

4-
interface TimelineLayerPanelProps {
5-
clipLabel: string;
6-
layers: DomEditLayerItem[];
7-
selectedLayerKey: string | null;
8-
onSelectLayer: (layer: DomEditLayerItem) => void;
9-
onClose: () => void;
10-
}
11-
123
const MEDIA_LAYER_TAGS = new Set(["audio", "canvas", "img", "picture", "svg", "video"]);
134

145
export function getTimelineLayerPanelSummary(layers: readonly DomEditLayerItem[]): string {
@@ -22,92 +13,3 @@ export function getTimelineLayerPanelSummary(layers: readonly DomEditLayerItem[]
2213
? "Single selectable media layer"
2314
: "Single selectable layer";
2415
}
25-
26-
export const TimelineLayerPanel = memo(function TimelineLayerPanel({
27-
clipLabel,
28-
layers,
29-
selectedLayerKey,
30-
onSelectLayer,
31-
onClose,
32-
}: TimelineLayerPanelProps) {
33-
return (
34-
<div className="flex h-full min-h-0 flex-col overflow-hidden bg-neutral-950">
35-
<div className="flex items-start justify-between gap-3 border-b border-white/10 px-3 py-3">
36-
<div className="min-w-0">
37-
<div className="text-[9px] font-semibold uppercase tracking-[0.18em] text-neutral-500">
38-
Clip layers
39-
</div>
40-
<div className="mt-1 truncate text-sm font-semibold text-neutral-100">{clipLabel}</div>
41-
</div>
42-
<button
43-
type="button"
44-
onPointerDown={(event) => {
45-
event.stopPropagation();
46-
}}
47-
onClick={onClose}
48-
className="flex h-7 w-7 flex-shrink-0 items-center justify-center rounded-md border border-white/10 bg-black/20 text-neutral-500 transition-colors hover:border-white/20 hover:text-neutral-200"
49-
aria-label="Close clip layers"
50-
>
51-
<svg
52-
width="14"
53-
height="14"
54-
viewBox="0 0 24 24"
55-
fill="none"
56-
stroke="currentColor"
57-
strokeWidth="1.8"
58-
strokeLinecap="round"
59-
aria-hidden="true"
60-
>
61-
<path d="M18 6 6 18" />
62-
<path d="m6 6 12 12" />
63-
</svg>
64-
</button>
65-
</div>
66-
<div className="border-b border-white/10 px-3 py-2 text-[11px] text-neutral-500">
67-
{getTimelineLayerPanelSummary(layers)}
68-
</div>
69-
<div className="min-h-0 flex-1 overflow-y-auto py-1">
70-
{layers.map((layer) => {
71-
const selected = layer.key === selectedLayerKey;
72-
return (
73-
<button
74-
key={layer.key}
75-
type="button"
76-
data-timeline-layer-row={layer.key}
77-
onPointerDown={(event) => {
78-
event.stopPropagation();
79-
onSelectLayer(layer);
80-
}}
81-
onClick={(event) => {
82-
event.stopPropagation();
83-
onSelectLayer(layer);
84-
}}
85-
className={`group flex w-full items-center gap-2 px-2.5 py-1.5 text-left transition-colors ${
86-
selected
87-
? "bg-studio-accent/14 text-studio-accent"
88-
: "text-neutral-300 hover:bg-white/[0.04] hover:text-neutral-100"
89-
}`}
90-
style={{ paddingLeft: 10 + layer.depth * 14 }}
91-
>
92-
<span
93-
className={`flex h-5 w-5 flex-shrink-0 items-center justify-center rounded-md border text-[9px] font-bold uppercase ${
94-
selected
95-
? "border-studio-accent/50 bg-studio-accent/18"
96-
: "border-white/10 bg-black/20 text-neutral-500 group-hover:text-neutral-300"
97-
}`}
98-
>
99-
{layer.tagName.slice(0, 2)}
100-
</span>
101-
<span className="min-w-0 flex-1 truncate text-xs font-medium">{layer.label}</span>
102-
{layer.childCount > 0 && (
103-
<span className="rounded-full border border-white/10 bg-black/25 px-1.5 py-0.5 text-[9px] font-semibold tabular-nums text-neutral-500">
104-
{layer.childCount}
105-
</span>
106-
)}
107-
</button>
108-
);
109-
})}
110-
</div>
111-
</div>
112-
);
113-
});

packages/studio/src/components/editor/domEditingElement.ts

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,7 @@ import type {
1212
import {
1313
buildStableSelector,
1414
escapeCssString,
15-
findClosestByAttribute,
1615
getElementDepth,
17-
getPreferredClassSelector,
1816
getSelectorIndex,
1917
getSourceFileForElement,
2018
isHtmlElement,
@@ -60,7 +58,7 @@ function isEmptyVisualContainer(el: HTMLElement): boolean {
6058
return true;
6159
}
6260

63-
export function hasRenderedBox(el: HTMLElement): boolean {
61+
function hasRenderedBox(el: HTMLElement): boolean {
6462
const rect = el.getBoundingClientRect();
6563
if (rect.width <= 1 || rect.height <= 1) return false;
6664
if (!isElementComputedVisible(el)) return false;
@@ -324,7 +322,3 @@ export function getDirectLayerChildren(
324322
isHtmlElement(child) && getDomLayerPatchTarget(child, options.activeCompositionPath) !== null,
325323
);
326324
}
327-
328-
// ─── Composition source helpers ───────────────────────────────────────────────
329-
330-
export { findClosestByAttribute, getPreferredClassSelector, getSourceFileForElement };

packages/studio/src/components/editor/manualEditingAvailability.test.ts

Lines changed: 1 addition & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -23,37 +23,15 @@ describe("manual editing availability", () => {
2323
expect(availability.STUDIO_PREVIEW_SELECTION_ENABLED).toBe(true);
2424
expect(availability.STUDIO_INSPECTOR_PANELS_ENABLED).toBe(true);
2525
expect(availability.STUDIO_MOTION_PANEL_ENABLED).toBe(false);
26-
expect(availability.STUDIO_TIMELINE_LAYER_INSPECTOR_ENABLED).toBe(true);
2726
});
2827

29-
it("keeps explicit truthy inspector env flags enabled", async () => {
30-
const availability = await loadAvailabilityWithEnv({
31-
VITE_STUDIO_ENABLE_INSPECTOR_PANELS: "1",
32-
VITE_STUDIO_ENABLE_TIMELINE_LAYER_INSPECTOR: "true",
33-
});
34-
35-
expect(availability.STUDIO_INSPECTOR_PANELS_ENABLED).toBe(true);
36-
expect(availability.STUDIO_TIMELINE_LAYER_INSPECTOR_ENABLED).toBe(true);
37-
});
38-
39-
it("allows explicit env flags to disable default-on inspector layers", async () => {
40-
const availability = await loadAvailabilityWithEnv({
41-
VITE_STUDIO_ENABLE_TIMELINE_LAYER_INSPECTOR: "off",
42-
});
43-
44-
expect(availability.STUDIO_INSPECTOR_PANELS_ENABLED).toBe(true);
45-
expect(availability.STUDIO_TIMELINE_LAYER_INSPECTOR_ENABLED).toBe(false);
46-
});
47-
48-
it("keeps timeline layer inspection off when the parent inspector flag is off", async () => {
28+
it("disables preview selection when the inspector panel flag is explicitly off", async () => {
4929
const availability = await loadAvailabilityWithEnv({
5030
VITE_STUDIO_ENABLE_INSPECTOR_PANELS: "0",
51-
VITE_STUDIO_ENABLE_TIMELINE_LAYER_INSPECTOR: "true",
5231
});
5332

5433
expect(availability.STUDIO_INSPECTOR_PANELS_ENABLED).toBe(false);
5534
expect(availability.STUDIO_PREVIEW_SELECTION_ENABLED).toBe(false);
56-
expect(availability.STUDIO_TIMELINE_LAYER_INSPECTOR_ENABLED).toBe(false);
5735
});
5836

5937
it("enables feature flags with explicit truthy env values", () => {

0 commit comments

Comments
 (0)