13 Commits
Author SHA1 Message Date
thePR0M3TH3ANandClaude Opus 5 90ce6def59 Add archive & rebroadcast for relay migration
A salvage tool in Settings. Sweeps every Artstr design still readable,
saves the signed events to a JSON bundle, and re-publishes them to the
current relays so designs survive a relay going dark.

Reads as widely as possible: the user's relays plus the old defaults,
deliberately including relays marked dead, since one unreachable from
this network may answer from another and a dying relay is exactly the
one holding events worth rescuing.

Signed in, it also sweeps the signer's own events by author, which is
the only way to reach private and premium designs - those carry
randomised d-tags and no public tag. The pubkey is requested from the
signer directly rather than read from state.community.myPubkey: a
connected extension does not populate that, and during testing the tool
reported "0 of mine" while the key in fact had 233 authored designs, 18
of them encrypted. Every private design would have been skipped.

Two rules the tool will not bend, because getting them wrong is worse
than not running:

- Retractions are honoured. A blanket `#k: 30078` deletion filter came
  back with 670 unrelated kind-5 events from across the network, all of
  which would have been rebroadcast; the lookup is now scoped to the
  authors actually collected and further filtered to deletions that
  target this archive. Those go out first, so a relay learns a design
  was withdrawn before anything can put an older copy back.
- Only the newest revision of each addressable design is sent.

Publishing uses one socket per relay - publishToRelays opens a fresh
connection per event, which for 230 events across 6 relays would be
~1400 connections and immediate rate-limiting. Each event is awaited
individually with a bounded in-flight window and a single retry on
rate-limit, so every one is accounted as accepted / rejected /
unanswered.

That last part took three attempts. Fire-and-forget with an
idle-timeout completion check kept closing the socket on the unsent
tail once designs ran to megabytes and acknowledgements lagged the
sends - runs reported 26, 46 and 202 acceptances out of 230 while
claiming success. Verified against a local mock relay that simulates
rate-limiting: 230/230 accepted, 0 unanswered, relay-side counts
matching exactly, and end-to-end 238 found / 230 sent / 230 accepted.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-08-02 12:13:13 -04:00
thePR0M3TH3ANandClaude Opus 5 8702043abf Import animated GIFs into the pixel editor
Add an inline GIF89a decoder - the mirror of the existing encoder, so
still no vendored dependency - and wire it into "From image / GIF...".
Every frame of an animated GIF becomes a frame in the pixel editor. A
browser <img> only ever exposes frame 0 to canvas, so decoding is the
only route to the rest; the decoder covers LZW, interlacing, local
colour tables, transparency and all three disposal methods.

The whole animation is quantized against one shared palette (per-frame
palettes made colours shimmer and burned through the 256-entry cap),
playback FPS is derived from the median GIF frame delay, and a Frames
control samples long animations down evenly. Frame count and working
resolution are bounded so a large GIF cannot exhaust memory, and
whatever gets dropped is reported rather than silently truncated.

Fix the reported pixel-editor import bugs:

- Dead canvas. applyLayout() tore the pixel editor down before its
  "layout unchanged" early return, and only the render() at the end
  rebuilds a standalone one - so clicking Pixel art while already in
  Pixel art left the grid on screen with nothing behind it and
  painting, the palette and import all silently did nothing.
- Locked W/H with no explanation, and a multi-image batch forced to the
  New frame target could never set dimensions at all. Batches can now
  target Whole sprite, and the lock states why and how to change it.
- Cover/Fit/Stretch previews were indistinguishable: the pixelized
  canvas rendered at its natural size (32 CSS px in a 250px box). Both
  panes now fill the box, and the source pane is framed exactly as the
  conversion frames it, so the two read as before/after.
- Photos were point-sampled on the way down, which threw away almost
  the whole image and read as noise. Area-average via progressive
  halving, switching to nearest at 1:1 and integer ratios so pixel-art
  sources stay crisp and import exactly.

Also fixed while verifying:

- Standalone pixel work was lost on refresh - pixelCommitIfStandalone()
  mutates state without calling render(), which is what writes the
  autosave. persistAutosave() existed for this case but was never
  called here.
- The quantizer always split to the requested colour count, padding
  small palettes with duplicate dead entries that cost event-size
  budget. It now keeps the source's exact colours when there are fewer
  than requested.
- sanitizePixelArtBlob truncated imported palettes at 64 though the
  model allows 256 (cells past the cut rendered transparent) and
  dropped per-frame durations.
- Stale grid-size pill after a resize, zoom not refitting when the grid
  grows, and a dead pixelImportFromImage() pointing at a nonexistent
  element.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
2026-08-02 11:02:40 -04:00
thePR0M3TH3AN 50eed8c017 docs: spec the Book Designer (unified cover + pages + PDF export)
New BOOK_DESIGNER_FEATURE.md drafts a top-level templateMode: 'book'
that orchestrates the existing cover designer, deck overview, and
custom-art canvas around a shared document spec (trim size, page
count, paper thickness, bleed). Spine width derives from page count
× paper thickness; the cover view goes read-only on the spine
column when in derived mode. Pages reuse the deck-sorter UI for
reordering; the per-page editor is the custom-art canvas bound to
a book-page:<id> target with prev / next page nav. Masters render
underneath each inheriting page and support {page-number} /
{page-count} / {book-title} token substitution.

PDF export ships in its own phase (E), backed by a vendored
pdf-lib (~80 KB). Single-file (cover + interior) and split (cover
PDF + interior PDF) output modes; bleed + crop-mark options;
v1 flattens text to vector for font-fidelity, with vector PDF
text as a follow-up.

Phased: A (spec + skeleton) → B (pages + editor) → C (masters) →
D (publish) → E (PDF export) → F (templates + deck-to-book
import). Non-goals: reflowable text, footnotes, automatic TOC,
CMYK / ICC, imposition, mixed page sizes in one book.

Linked from README's "Drafted-but-unbuilt" list and TODO.md.
2026-06-02 10:29:01 -04:00
thePR0M3TH3AN 007ad1d1e2 Cleanup: drop superseded specs + refresh README
Removed three superseded spec files now that the work they
described is either shipped (under newer specs) or formally
replaced:

  docs/ZAP_GATED_TEMPLATES_FEATURE.md
  docs/ZAPS_NWC_FEATURE.md
  docs/ZAP_GATED_PREMIUM_FEATURE.md

The history is preserved in git. The current canonical premium
plan is docs/PREMIUM_DESIGNS_FEATURE.md (which absorbed the
zap-gated+NWC infrastructure plus added the soft-gate KDF +
encrypted envelopes + purchase vault).

README's docs paragraph now lists every active spec by status —
shipped / partial / drafted — and adds the transparency-iframe
baseline stub that landed alongside the embed feature.
2026-06-01 16:11:35 -04:00
thePR0M3TH3AN 3b47a314c0 Catch up TODO + README + spec banner on the premium-templates arc
Pre-merge docs sweep before zap-gated lands on main:

- TODO.md: move Premium out of "Drafted-but-unbuilt" into "Shipped
  (recent)" with a full summary of what landed (soft-gate, watermarked
  previews, NWC split-zap with 30% platform fee, purchase vault with
  auto-split, profile menu, login picker, Settings, mobile polish).
  Leave Phase 4 E2E + a few confirm()-modal replacements as a new
  "Premium-templates polish" section.
- docs/PREMIUM_DESIGNS_FEATURE.md: flip the status banner to
  "Shipped on zap-gated, merged into main 2026-05-29" and map each
  spec step (0-4) to where it lives in src/.
- README.md: add a Premium encrypted designs section; mention NWC,
  vault, login picker, profile dropdown, and Settings modal in the
  Nostr / Lightning sections; drop "NWC zaps / zap-gated templates"
  from the unbuilt list in the Files section.
2026-05-29 10:37:27 -04:00
thePR0M3TH3ANandClaude Opus 4.7 6a1352904e Docs: ship pixel-art Phases A–D, prune stale TODOs, update README
PIXEL_ART_FEATURE.md: rewrite Implementation status to reflect that
Phases A–D all shipped (embedded layer, standalone design, raster
export + editor extras, animation, image → pixelize), with the
backlog (WebP/APNG, Blossom offload, animated pixel layers driving
Stack actions) called out as deferred.

TODO.md: drop stale items now that they're resolved —

- Pixel Art (moved to a "Shipped (recent)" section pointing at the
  spec doc).
- Pixel editor layout expansion (subsumed by the collapsible
  sidebar — both the pixel editor and vector canvas can now use
  the full viewport width).
- Print / Save event ID wrapping (the `<dd>` already uses
  `overflow-wrap: anywhere; word-break: break-word`).
- TMDB auto-fill cleanup (the doc was already deleted).

The Color picker fixes item is kept but narrowed to the vector
tools — the pixel editor's in-app HSV picker shipped in Phase A.

README.md: add Pixel Art everywhere it's relevant —

- One-liner mention in the intro paragraph.
- New "Pixel art" Designer-tab layout entry alongside Slide / Disc
  design.
- `pixelart` layer type added to the Layers list.
- New dedicated "Pixel art" section before Editor canvas, covering
  tools / transforms / animation / export / import / undo /
  animated previews.
- Editor canvas section mentions the new sidebar collapse toggle.
- Schema section lists `pixelart` template mode and layer type,
  documents the `pixelArt` data-model shape, and notes that the
  inline GIF89a encoder lives in `index.html` (not a vendored dep).

Co-Authored-By: Claude Opus 4.7 <[email protected]>
2026-05-26 10:54:10 -04:00
thePR0M3TH3ANandClaude Opus 4.7 9bf99f1abb Add Slide Decks & Presenter Mode (v1: Phases A–D)
Build a Nostr-native presentation system on top of the existing canvas
editor:

- Slide (templateMode 'slide') — a 16:9 Custom Art canvas with speaker
  notes; publishes/forks/loads as casewrap-slide.
- Deck Builder (templateMode 'deck') — a Template-tab container with an
  inline ordered slide list. Slide-sorter view: add blank, import from
  Nostr or file (non-16:9 imports letterboxed), duplicate, delete,
  drag-reorder, inline-rename; edit a slide in the canvas editor with
  write-back. Self-contained save/load/publish/fork as casewrap-deck;
  deck feed-card and publish previews show the first slide + count badge.
- Deck theme — deck-level font + background, render-time composition,
  per-slide ignoreDeckTheme opt-out.
- Presenter Mode — full-screen runtime: themed slide, notes, next
  thumbnail, counter; keyboard/click/on-screen nav; Presenter ⇄ Audience
  view toggle (slide-only full-screen with auto-hiding chrome). Launches
  from the deck tool palette and a deck's community-browser preview.

Supporting changes:
- New categories: slide ("Slide design") and slide-deck ("Slide deck");
  both use the free-form Custom tag field, not media identifiers.
- Swap the Template/Designer tab icons; 50% larger.
- Remove the IMDb/OMDb metadata import (button, handler, omdbApiKey);
  the imdbId field stays.
- Update README, SLIDE_DECK_FEATURE.md status, and TODO.md.

Co-Authored-By: Claude Opus 4.7 <[email protected]>
2026-05-21 22:10:06 -04:00
thePR0M3TH3ANandClaude Opus 4.7 ef7d4803f7 Text/Shape/Hand tools, Designer-tab restructure, rename to Artstr Studio
- New left-palette tools: Hand (pan), Shape (drag to draw a primitive),
  Text (click to place). Removed the redundant sidebar add-buttons.
- Pencil strokes now keep a constant on-screen thickness (pixel-space
  viewBox) instead of scaling with stroke length/aspect.
- Restructured tabs: "Disc Designer" -> "Designer", which now hosts a
  Layout panel with Custom Art (default) + Disc Design; Custom Art moved
  off the Template tab. Underlying appMode/save-format unchanged.
- Renamed the app from CaseWrap Studio to Artstr Studio (brand text only;
  Nostr tags and localStorage keys kept for compatibility); smaller
  one-line logo wordmark.
- README updated for the new tabs, tools, and keyboard shortcuts.

Co-Authored-By: Claude Opus 4.7 <[email protected]>
2026-05-20 15:30:46 -04:00
thePR0M3TH3ANandClaude Opus 4.7 162da4b9e4 QR code layers, combined-wrap panel, profile-close fix, TODO
QR code layer (Phase A):
- New `qr` layer type. Add QR button alongside Image / Text / Color /
  Shape in every layer panel. Spawns 1:1 with a placeholder URL.
- Controls: data textarea, error-correction level (L/M/Q/H), quiet
  zone, module + background colors, transparent-background toggle.
- Renders as crisp SVG on the editor and all five preview surfaces
  (dark modules merged into one path); canvas/PDF/JPEG export draws
  it cell-by-cell. Round-trips through JSON and Nostr publish/fork;
  old clients skip the unknown type. Works with drag / resize /
  rotate / opacity / aspect-lock / clip / clipboard / undo-redo.

Combined-wrap layer panel:
- In cover mode with Artwork mode "One combined wrap image", the
  layer panel collapses the separate Back / Spine / Front panels
  into a single "Cover trim area" panel — the wrap is one open
  canvas, so the sub-regions aren't meaningful. The combined panel
  still lists any pre-existing back/spine/front layers via a
  matchKeys set so they aren't orphaned from the UI.

Profile modal close fix:
- closeProfilePage used history.back(), which navigated the browser
  out of the app entirely when the profile was cold-loaded from a
  shared /u/<npub> link (that entry being first in the tab's
  history). Switched to history.replaceState to "/" — cleans the
  URL in place without navigating or firing popstate. Matches how
  closeNostrPreview already handles the /share/ URL.

Docs:
- Add TODO.md tracking deferred work: QR Phase B/C, IMDb-import
  removal, profile-page polish, edit-flow polish, and the unbuilt
  badges / collections / zap-gated / NWC-zaps features.
- Remove docs/UNDO_REDO_FEATURE.md and docs/QR_CODE_LAYER_FEATURE.md
  (shipped) and docs/TMDB_AUTOFILL_FEATURE.md (declined).
- README: document QR layers, undo/redo, fit-to-view + zoom toolbar,
  and the off-canvas veil; refresh the schema and docs references.

Co-Authored-By: Claude Opus 4.7 <[email protected]>
2026-05-19 22:09:15 -04:00
thePR0M3TH3ANandClaude Opus 4.7 a02c562a9f Custom Art metadata simplification, JPEG mask fix, README rewrite
Custom Art project metadata:
- Hide the "Add Media Identifiers" panel when in Custom Art mode —
  IMDb / UPC / TheTVDB / MusicBrainz don't fit wallpaper / banner /
  logo work.
- Show a single optional Custom tag field in its place. Stored as
  state.meta.customTag, round-trips through save/load, and emits to
  Nostr as both an NIP-73-style 'i custom:<tag>' identifier and a
  topical 't <tag>' tag (lowercased, hyphenated, capped at 64 chars).
- Hide the IMDb import button + hint in Custom Art mode.
- Auto-select the "Custom art" category the first time the user
  enters customart mode without one set.

JPEG export mask fix:
- body.export-print > *:not(#exportPrintContainer) { display: none }
  was hiding the global SVG <defs> container that holds <clipPath>
  definitions for layer masks. With the defs invisible, every
  clip-path: url(#…) reference resolved to nothing during print,
  so the PDF that the JPEG flow re-rasterizes had unclipped layers.
  Carve #globalClipDefs out of the exclusion selector and force
  it to zero-size + overflow:hidden so it stays in the DOM but
  takes no space. Direct "Print / Save PDF" was unaffected because
  it doesn't use the export-print mode.

README rewrite:
- Brings the README in line with what the app actually does today:
  Custom Art mode, vector shape primitives + gradients + strokes +
  custom SVG upload with per-element editor, clipping/masking,
  layer clipboard, profile pages at /u/:npub, Lightning tips with
  WebLN auto-pay + NIP-57 zap tracking + Zapped tab, edit-in-place
  via NIP-33 replaceable semantics, the publish-confirm modal, the
  current schema version (5 / min 4), and the vendored qrcode lib.

Remove docs/VECTOR_SHAPES_FEATURE.md — the feature shipped.

Co-Authored-By: Claude Opus 4.7 <[email protected]>
2026-05-19 14:37:36 -04:00
thePR0M3TH3AN 6e89296d3b Update README to match current app workflows 2026-05-16 12:26:51 -04:00
thePR0M3TH3AN 8bea24d55a update 2026-05-14 21:56:47 -04:00
thePR0M3TH3AN 256f85b341 update 2026-05-14 12:58:47 -04:00