Something went wrong. Try again.
Monorepo for Aesthetic.Computer aesthetic.computer
Something went wrong. Try again.
Markdown
Tape MP4 Conversion for ATProto Sync #
Current State #
- Tapes are uploaded as ZIP files containing:
frame-{n}.png- Scaled frames (6x original size)timing.json- Frame durations and timestampsmetadata.json- Original dimensions, scale, frame count, duration
- MongoDB
tapescollection stores:{ code, slug, when, bucket, user, nuked } - NO automatic MP4 conversion or ATProto sync yet
Desired Architecture #
Regular Tape Creation (track-tape.mjs) #
// Client uploads ZIP to storage
// Server creates MongoDB record
// NO MP4 conversion
// NO ATProto sync
{
code: "abc",
slug: "wand-2025.10.23.12.30.00.123",
when: Date,
bucket: "user-aesthetic-computer",
user: "auth0|123",
nuked: false
}
Sync Script (sync-atproto.mjs) #
When syncing tapes to ATProto:
- Download ZIP from storage
- Extract frames from ZIP
- Convert frames to MP4 using ffmpeg
- Upload MP4 blob to ATProto
- Create ATProto record with:
zipUrl: Direct link to download the ZIPvideo: MP4 blob (for viewing in ATProto apps)acUrl: Permalink to view on aesthetic.computer
ATProto Record Structure #
{
$type: "computer.aesthetic.tape",
slug: "wand-2025.10.23.12.30.00.123",
code: "abc",
zipUrl: "https://user-aesthetic-computer.sfo3.digitaloceanspaces.com/auth0|123/slug.zip",
acUrl: "https://aesthetic.computer/!abc",
when: "2025-10-23T12:30:00.123Z",
video: { // MP4 blob
$type: "blob",
ref: { $link: "bafkreiabcdef..." },
mimeType: "video/mp4",
size: 5242880
},
ref: "mongoId"
}
Implementation Tasks #
Phase 1: Basic Sync (Without MP4) #
Phase 2: MP4 Conversion (Local) #
Phase 3: Production Deployment #
Technical Notes #
ffmpeg Command #
# Create MP4 from PNG sequence with variable frame durations
ffmpeg -r 60 \
-i frame-%d.png \
-c:v libx264 \
-pix_fmt yuv420p \
-movflags +faststart \
output.mp4
ZIP Structure #
wand-2025.10.23.12.30.00.123.zip
├── frame-0.png
├── frame-1.png
├── frame-2.png
├── ...
├── timing.json
└── metadata.json
timing.json Format #
{
"frames": [
{ "index": 0, "duration": 16.67, "timestamp": 0 },
{ "index": 1, "duration": 16.67, "timestamp": 16.67 },
...
],
"totalDuration": 4000
}
Future Considerations #
- Caching: Store converted MP4s to avoid re-conversion
- Background Jobs: Queue MP4 conversions for async processing
- Quality Options: Allow different MP4 quality levels
- Alternative Formats: Support WebM or other video formats
- Frame Rate: Consider variable frame rates from timing.json