Files
Artstr-Studio/TODO.md
T
thePR0M3TH3AN 467fbcf5e4 Draft PPTX import spec
Adds docs/PPTX_IMPORT_FEATURE.md as the canonical plan for the next
big arc: a phased editable .pptx importer that lands PowerPoint decks
as editable Artstr deck JSON.

Key decisions baked in:

- Images and unsupported objects (charts / SmartArt / tables / video)
  import as placeholder image layers pointing at a hardcoded URL
  (postimg.cc for now). Original PowerPoint media filenames carry
  over into the layer name so the user can correlate placeholders
  with their source deck.
- fflate (~10 KB) vendored as src/vendor/fflate.min.js. JSZip is too
  heavy for the single-file ethos.
- Importer code lives in src/pptx-importer.js as an IIFE that
  exposes window.ArtstrPptxImporter. The Import PPTX button
  dynamically injects both scripts on first click, so the main
  index.html bundle does not grow for the 90 % of users who never
  import a PPTX.
- Notes folded into Phase 2 alongside text (single extra relationship
  lookup, Presenter Mode already renders slide.notes).
- No Blossom / NIP-96 prereq, no base64 bloat, no publish-size guard.
  Imported decks are normal Artstr deck payloads with remote URLs.
- Import-only for this arc. PPTX export (Artstr -> .pptx) is a
  separate later arc with its own complexity.

TODO.md gets a Drafted-but-unbuilt entry pointing at the new spec.
2026-05-29 11:21:54 -04:00

234 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Artstr Studio — TODO
Running list of deferred work. Detailed specs for the larger items live in
`docs/`. Each entry notes scope and where the spec is (if any).
## Adam's working list
_(Empty — see "Shipped (recent)" below for the items that just
landed. Drop new items in here as they come up.)_
## QR code layer — remaining phases
Phases A and B shipped (the `qr` layer type: data, error-correction level,
quiet zone, module / background colors, transparent background, renders
on every surface + canvas export, JSON round-trip; plus "Insert npub" and
"Insert share link" buttons under the QR data field).
- **Phase C — visual polish.** Optional center logo overlay and rounded
modules. Riskier: a logo eats into the error-correction budget, so it
should nudge the ECC level up. Skippable.
## Editor / tool UX
Small editor-usability improvements — no spec doc; scoped here.
Shipped: on-canvas drag-resize handles for every layer type, text-box
resize that never rescales the point size, the expanded Text tool panel
(font / size / color / alignment / bold / italic), a collapsible sidebar
toggle that fits the early-web aesthetic. Add new editor-UX items below.
## Profile pages — deferred polish
(Core profile pages at `/u/<npub>` already shipped.)
- Make author chips clickable in the **community thread view** (comments and
reposts) — currently only feed-card and preview-meta author chips route to
`openProfilePage`.
- **About-text clamp** — long bios overflow the profile header; clamp to ~4
lines with a "Show more" toggle.
- **Profile-grid pagination** — an author with 100+ designs renders them all
at once; cap the initial render and add a "Show more" pager.
## Edit-published-designs — deferred polish
(Core edit-in-place via NIP-33 replaceable semantics already shipped.)
- Replace the remaining `confirm()` calls in the edit / publish flow with the
styled in-app modal pattern, for consistency with the close-project and
publish-confirm modals.
- "Editing a previously-deleted design" warning — if the user opens Edit on a
design they had tombstoned with a kind-5, warn that publishing will
republish it.
## Pixel art — future polish
- **`pixelsB64` size-fallback encoder.** The spec calls for each frame
to store whichever is smaller: `pixels` (RLE pairs) or `pixelsB64`
(base64 of the raw `Uint8Array` of indices). Only RLE is implemented
today. For noisy / photo-pixelized content with many palette colours,
base64 is ~5× smaller — a 24-frame 64×64 sprite tested at 785 KB
RLE would drop to ~150 KB. Worth shipping alongside a live event-size
readout in the editor (soft warn at 50% of relay budget, hard block
at 90%) so users see the budget before publish.
## Drafted-but-unbuilt features
Each has a full spec in `docs/`.
- **PPTX import** — `docs/PPTX_IMPORT_FEATURE.md`. Phased editable
importer that converts a `.pptx` package into an Artstr deck.
Images and unsupported objects (charts, SmartArt, tables, video)
land as placeholder image layers pointing at a hardcoded URL;
user replaces each placeholder by editing the layer's src. No
Blossom prereq, no base64 bloat, decks publish to Nostr normally.
fflate vendored bundle + a lazy-loaded `src/pptx-importer.js`
module so the main app weight doesn't grow.
- **Artstr Stacks** — `docs/STACKS_FEATURE.md`. Interactive fullscreen
page/card stacks (HyperCard for Nostr) — the Slide Deck extended with
layer actions and an interactive viewer.
- **Badges (NIP-58)** — `docs/BADGES_FEATURE.md`. Award / display Nostr
badges on profile pages.
- **Collections (NIP-51 sets)** — `docs/COLLECTIONS_FEATURE.md`. Let users
organize favorite community templates into named sets.
## Premium-templates polish
The premium-encrypted-designs arc shipped in 2026-05; see
`docs/PREMIUM_DESIGNS_FEATURE.md` for the canonical spec. Open
follow-ups worth their own work:
- **Phase 4 E2E test matrix** — real-money round-trip through CoinOS:
publish premium → unlock from another browser → vault sync. Plus
the edge-case matrix from §19 item 4 of the spec (wallet budget
exhausted, platform fail after creator paid, partial-pay resume,
missing lud16, cache wipe → relay fast-path).
- **Confirm()-style modals** — the unlock confirm and a few other
premium-related prompts still use native `confirm()`. Replace with
the styled in-app modal pattern.
- **Future-proofing** — when an epoch's soft-gate pepper gets reverse-
engineered we'll ship a new epoch. The infra is in place; the
rotation playbook should land as a SECURITY.md when we do it.
## Phase-3+ work on shipped features
- **Private (encrypted) publishing — Phases 3 & 4.**
`docs/PRIVATE_PUBLISHING_FEATURE.md`. Phases 1 (private-to-me) and
2 (toggle public ⇄ private) shipped in commit `3e6e89e`. Still
unbuilt: Phase 3 (share with selected pubkeys) and Phase 4 (NIP-59
gift-wrap metadata privacy + Blossom/NIP-96 offload for oversized
encrypted blobs).
## Shipped (recent)
- **Premium encrypted designs — static soft-gate + NWC split-zap +
purchase vault.** Spec lives in `docs/PREMIUM_DESIGNS_FEATURE.md`.
Creators tick "Premium encrypted" + a soft-gate ack in the publish
modal, set a minimum sat amount; we AES-256-GCM encrypt the
payload (HKDF over an obfuscated per-epoch pepper + per-design
salt + the event coordinate as AAD), render a watermarked low-res
JPEG preview embedded in the envelope, and emit the §5.1 tag set
with two zap-split tags (creator 70 % / platform 30 %).
Consumers see a gradient-stroked card + ⚡ PREMIUM ribbon with an
"Unlock for N sats" CTA on all three import paths (feed card,
preview pane Use/Fork, preview pane Save JSON). Unlock fires both
pay_invoice legs in parallel over NWC, derives the soft-gate key
locally on receipt confirmation, decrypts in place with a reveal
animation. Cross-device sync via a NIP-44 self-encrypted purchase
vault (kind-30078 `d=artstr:purchase-vault:v1`) that auto-splits
into per-item events when over 40 KB. Address-tolerant unlock
lookup so edit-in-place doesn't invalidate prior purchases.
Hydrates on Nostr login with a "Restored N unlocks ✓" toast.
Soft-gate framing is honest in every UI surface: it raises
friction against drive-by scraping, NOT strong DRM. Foundation
layers (noble bundle, NWC client + wallet settings UI with
CoinOS-first onboarding, platform-fee dual-zap orchestrator, NWC-
default Lightning tips, login-method picker, profile dropdown
menu with View Profile / Settings / Logout, the Settings modal
itself, the new Premium tab + mobile-friendly browser layout)
all shipped as part of the same arc. ~30 commits on the
`zap-gated` branch, merged into main 2026-05.
- **Pixel-art dropdowns — no more sidebar clipping.** The pixel-editor
resize-grid and PNG-export menus were `position: absolute; right: 0`
inside their toolbar wrap. When the toolbar wrapped and the trigger
button landed at the left of its row, the menu slid leftward under
the main sidebar. Switched both menus to `position: fixed` with a
JS-placed coord that anchors to the button's right edge by default,
flips to its left edge if anchoring right would clip past the
sidebar (sidebar's actual right edge, not just the viewport),
and clamps inside the viewport on both sides. Also auto-closes any
open menu on window resize to avoid stranded fixed-position remnants.
- **Top-right action strip — permanent, never wraps.** Pulled the
canvas-size readouts and the undo / redo pair out of the topbar's
flex flow and pinned them in a fixed strip directly under the Nostr
widget, right-anchored, with `flex-wrap: nowrap`. Order: canvas-size
pills on the left, undo / redo on the right (so undo / redo hug the
viewport edge). The topbar's right padding now tracks the wider of
the Nostr widget or the strip via the existing
`--nostr-widget-space` var, so the project title never slides under
it.
- **Click canvas background → deselect.** The existing #sheet click
handler missed clicks in the gutter between sheet edge and
previewShell edge; added a #previewShell handler.
- **Crop marks for Custom Art / Slide canvases.** New `.canvasCrops`
corner marks inside .sheet, scoped to those template modes. The
existing showCrops / printCrops toggles drive screen + print
visibility (relaxed from cover-only to a new `.crops-toggle`
class).
- **Strip selection chrome from PDF Print / JPEG-fallback output.**
Dead `body.exporting` CSS rules were renamed to actually match the
class JS sets. Wired both the regular printBtn flow and the
JPEG-PDF flow to set the class. Two-class split (`body.exporting`
for chrome-stripping in either flow, `body.export-print` for the
heavier container-isolation only the JPEG-PDF flow does) avoids the
blank-print regression that a single class caused.
- **Custom Art: match canvas to image's natural dimensions.** New
"Match canvas to image size" button on the image-layer panel (Custom
Art mode only; Slide is 16:9 locked). Loads the image via
loadImageWithCors, clamps to CUSTOM_ART_MAX, pushes one undo entry.
- **JPEG export — rich text rendering (P2).** Canvas-based engine
that walks the layer's HTML into styled runs (bold/italic/underline,
bullets, numbered lists, line breaks), lays them out with
ctx.measureText + word wrap, and draws each item with its own font
+ underline. Dispatches to plain `fillText` when no inline marks
are present. SVG-foreignObject was tried first; it taints the
canvas in Chromium so we built the run-layout engine instead.
- **Independent-axis corner-node resize.** Corner handles default to
independent axes (each axis follows its own drag delta); Shift+drag
locks aspect (Figma / Photoshop / Keynote convention). The sidebar
🔒 toggle still governs typed W/H input cascades.
- **JPEG export — DPI / quality selector (P4 polish).** 96/150/300 dpi
presets in a dropdown next to the Export JPEG button.
- **JPEG export — one-click direct rasterizer (P1).** Replaces the
print-to-PDF-then-re-pick flow for Cover, Disc sheet, Jewel,
Disc design, Custom Art, and Slide canvases. The infrastructure
was already 90% built (drawLayerToCanvas + four canvas-type
rasterizers existed but were never wired to any entry point);
P1 added the missing Custom-Art rasterizer + the orchestrator
that picks the right rasterizer per templateMode, pre-flights
CORS via the existing _exportFailedImages set, and falls back to
the print modal when any image can't be embedded directly.
- **Slide deck PDF export** — multi-page PDF, one page per slide. The
existing Print / Save PDF button is context-aware: in the Deck Builder
it builds a hidden print-only container with one page per slide (themed
via `composeSlideForDeck`, each page sized to the preview's native
dimensions so the slide fills the page exactly) and emits one PDF via
`window.print()`. Inside a single-slide editor, the button still prints
just that slide.
- **Copy / paste transform consistency** — paste now computes a single
group bounding box across all clipboard items, applies one shared scale
(only shrinks, never enlarges) and one shared translation, so cross-
target paste keeps every layer's relative position and size to the
others intact.
- **Pixel-editor colour picker** — ported the OS native `<input type="color">`
over from the vector tools (same swatch styling; opens the OS picker with
its built-in eyedropper on click). Removed the Screen-Capture-API screen-
eyedropper workaround (~170 lines of dead code). Palette swatches and
the in-canvas eyedropper tool now sync the picker too, so grabbing a
palette colour as the starting point for a tweaked variant just works.
- **Pixel Art** — `docs/PIXEL_ART_FEATURE.md`. Phases A–D all shipped:
embedded `pixelart` layer + standalone `casewrap-pixelart` design,
PNG / sprite-sheet / GIF export, drawing tools (line / rect / ellipse,
flip / rotate, grid resize), animation (multi-frame timeline, playback,
onion-skin), image → pixelize, and animated previews in every preview
surface. Undo / redo integrated with the top-level toolbar.
- **Pixel editor layout expansion** — addressed by the collapsible
sidebar (gives both the pixel and vector editors a lot more breathing
room when needed).
- **Print / Save event ID wrapping** — the event-id `<dd>` already uses
`overflow-wrap: anywhere; word-break: break-word`, so no horizontal
scroll.
- **TMDB auto-fill cleanup** — `docs/TMDB_AUTOFILL_FEATURE.md` removed.