The site name is Sketchlet, displayed as "sketchlet". Existing draft storage keys retain their original names for compatibility. The unused local-only preview module has been removed; any old preview records remain untouched in browser storage but are not used by the current application.
Use the drawing studio's current retro-web treatment throughout the application. src/styles/retro.css is the current visual reference.
- Unkempt from Google Fonts for headings, names, controls, and short lowercase statuses, with bold weight for the sketchlet header. IBM Plex Sans provides sentence-case explanatory content; IBM Plex Mono handles code and technical identifiers. The brand name stays lowercase. See
src/styles/content.cssfor these reading styles. - Non-drawing buttons opt into
.site-buttonalongside.web-button: lavender is the supporting-action default,.primaryis green,.utilityis blue, and.dangeris peach for destructive or irreversible confirmations. A subtle irregular outline overlays the square raised bevel without changing geometry. Pressing reverses the bevel; keyboard focus stays explicit. Admin confirmation follows the selected action. Canvas tools, history controls, color menus, and full-screen controls do not opt in. Labels must explain the action without relying on color. - Profile content order is account confirmation, profile editing and personal drawings, then a fully visible recovery section with a pale blue background. At 900px and wider, editing and drawings share two columns; mobile keeps that same reading order in one column. Recovery has no disclosure control or reveal animation. Initial navigation retains the shared pencil-stroke loader until account resolution, profile details, drawing history, and (when signed in) guest review have settled. Errors reveal their retry controls rather than trapping the page behind the loader; thumbnails remain lazy. Later profile actions do not restart the full-page loader.
- The fresh-day welcome pairs today's drawing with recent favorites in equal-width panels from 900px, stacked on smaller screens. Favorites prioritize public drawings from the last 14 Eastern calendar days, filling any remaining slots with older work up to four drawings total. Both pools require an average of at least four stars and at least two ratings, ordered by average, rating count, submission time, then ID. Future prompt dates are excluded.
/api/highlightsreuses public visibility, excluding moderation removals and merge exclusions. The lazy panel refreshes every minute while visible, defers replacement of keyboard-focused links, and stops on leaving the welcome view. Failure or no qualifying work never blocks drawing; no editor or saved-drawing page gains this polling. - Profile section dividers use a single irregular pen stroke defined in
content.css, including the linking-notice heading divider. The decorative SVG scales to the section width without changing stroke weight; alternate orientations avoid identical-looking separators. Beveled panel borders remain intact, and forced-colors mode uses a visible system-color line. - Raised beveled buttons, inset fields and canvas, square corners, hard shadows.
- Purple title bars and accents, muted gray-lavender panels, and staggered diamond background tiles with uneven pen outlines. Lavender, dusty blue, and muted plum families vary in shade, with plain, hatched, and stippled finishes on a pale lavender ground. The seamless 192px SVG tile lives in
src/assets/diamond-pattern.svg; textures use lightweight vector marks rather than filters. Supported browsers gently translate a fixed decorative layer by up to 48px over page scroll; no JavaScript scroll listeners or drawing work are involved. Reduced-motion preferences and unsupported browsers get the static tile; forced-colors mode uses Canvas. The animated layer is disabled during loading and full-screen drawing. - Selected controls appear pressed in. Keyboard focus remains clearly visible.
- Concise functional labels; avoid decorative slogans, mascots, and filler copy.
- Preserve large touch targets and responsive phone, tablet, and desktop layouts.
- Use one hand-drawn separator per element: below the header, above the footer and account notices, and at section boundaries or beneath important-notice headings. Avoid framing the same content with paired strokes. The root diamond pattern fills unused viewport space below short pages; decorative strokes stay inside the header/footer and add no spacer or extra scroll area.
-
The Info page opens with an illustrated navigation grid: a tall free-draw tile, guide and announcement tiles beside it, and a wide about tile below. At 600px and narrower the tiles stack. Original 32×24 pixel sprites in
backend/info-hero.mjsuse a shared eight-color palette, stepped silhouettes, flat shadows, and abstract details. Row runs become crisp-edged inline SVG rectangles; no image service or client script is needed. Each entire tile is a keyboard-accessible anchor to its section, with display-font headings and readable supporting text. -
/infois the published, server-rendered hub for free draw, a drawing-tool guide, site information, and announcements. It has a top-nav link and works without JavaScript. The administrator can draft, publish, schedule, edit, and unpublish announcements; Info lists public posts and home previews the latest title. SeeANNOUNCEMENTS.md. The diamond background has a muted overlay. A passive page-scroll signal brightens the decorative layer by 3% over 600ms in supported browsers. After 900ms without scrolling, it fades back over 1.2 seconds; direction changes and native scrollend events do not restart the effect. Reduced motion and full-screen drawing suppress it. -
/free-drawreuses the editor viaeditor-loader.js, with a dedicated controller and an isolatedfree-draw-v1IndexedDB draft. It never resets at midnight or publishes to the gallery. Own submitted drawings offer blank-canvas and copy-image entry points; there is no footer link. Explicit starts require confirmation before replacing a saved practice canvas, while the bare URL restores it. Image starts verify ownership and visibility, normalize the published image into a 1200px PNG first stroke, and retain it locally. The original is unchanged; erasing, fill, clear, undo, download, and reload use the shared rendering pipeline. Original strokes/background are flattened. Decoded seed images are weakly cached and reused by the incremental renderer. Full-screen mode labels it “free draw.” Daily drafts keep their existing date-scoped keys. -
Profile drawing previews show the five most recent entries, with an inline link to
/gallery?view=mine. The personal gallery uses the same identity-scoped endpoint with 24-entry cursor pagination. Hidden moderation notices remain owner-only and account-merge exclusions remain omitted. The profile's retry button is only for failed requests; browsing older entries happens in the gallery. -
One shared daily action-and-noun prompt (for example, "crying dog" or "laughing kite"), changing at midnight America/New_York. Pairings are deterministic for the date and can be playful or impossible.
-
One final submission per browser identity per prompt; editing and local draft saving before submission.
-
Guest use remains supported. Optional Clerk accounts support shared ownership across signed-in devices and explicit guest-work linking; friend groups are the next feature stage.
-
Unique public URL for each submitted drawing, with its average rating and vote count.
-
After submission, show the drawing, ratings, participation streak, and an option to rate more drawings.
-
Rate drawings individually with 1–5 stars or skip. Mix under-rated drawings with well-rated drawings; exclude the visitor's own submission.
-
Archive prompts allow rating but not new drawings in the MVP.
-
Participation streaks are based on consecutive Eastern prompt dates.
-
Neon Postgres stores prompts, drawing metadata, profiles, and ratings; a private object-storage bucket holds submitted PNGs. Drafts remain on the current device in IndexedDB.
-
Vercel is the selected web/API host. Deployment preparation and validation steps are in DEPLOYMENT.md; the user runs terminal commands and initiates deployment.
-
Rating requires a saved profile name, but does not require submitting a drawing. Shared links support rating and editing a previous vote; users cannot rate their own drawings.
- Daily prompt and date surrounding the existing drawing studio.
- Submission review explaining that submitting is final.
- Submitted drawing view with sharing, ratings, and streak.
- One-at-a-time rating view with star selection and skip.
- Empty states for a new community and an exhausted rating queue.
- Archive browsing and individual drawing pages.
- Editable profile with a local-only photo and a paginated list of this browser's drawings.
- Full-screen drawing on portrait phones and tablets; landscape requires at least 1101px width. Rotating into narrower landscape returns to normal view with the drawing and undo history preserved. Narrow screens use two tool columns, with swatches in color menus.
- Separate gallery submission and PNG download buttons in normal view. A universal footer with About, Privacy, Community & Terms, Contact, and copyright follows page content, matches the header width, and is hidden during full-screen drawing. Daily drawing rules remain in the home introduction and About page. The shared page template owns the footer, so loading the editor never creates another copy.
Information pages render their content immediately without the drawing loader, editor, or database requests. About, Privacy, and Community & Terms remain visibly marked, unindexed drafts. Contact adds only its small submission module: confirmed success replaces the form with a thank-you and home link, while errors preserve entered text. The native Formspree POST is retained for hosted spam checks and no-JavaScript use. See PUBLIC-PAGES.md and CONTACT.md.
Home and gallery have separate generated documents and JavaScript entry points. Home requests submission status before opening IndexedDB or loading the editor. The small draft-storage helper is imported at startup, but completed days do not open or read drafts. On an unfinished day, an existing draft opens the editor; otherwise the instructions appear and editor files preload without mounting or evaluating the editor. Gallery and shared-drawing pages request their own data without initializing the editor or requesting today's status. Submission controls are loaded only alongside the editor. Shared community/profile rendering remains in src/gallery.js; further component extraction is separate work.
Gallery submission is the primary action and PNG download is an optional local export. Keep previous local drafts and preview records intact. No sample votes or drawings are migrated automatically. Follow README and DEPLOYMENT.md for setup and release verification.
strokeSpacing() in src/brushes.js supplies spacing for both complete replay and the incremental pencil cache. src/text-format.js supplies count labels and creator captions for gallery text, share cards, and server-rendered link titles; callers remain responsible for HTML escaping. These shared rules keep rendering and wording consistent without merging page controllers or legacy brush renderers.
Drawing performance: completed strokes are cached. Live seeded pencil strokes append only new distance-spaced grain to the existing working buffer; other styles retain their single-fill rendering to preserve opacity and edges. Cache invalidation rebuilds from stroke data after context recovery or a history change. No additional canvas or persisted draft format is needed. Browser checks compare incremental pencil pixels against full replay and count grain operations; real-phone responsiveness still requires manual validation.
Deferred, lowest-priority idea: collect lightweight creation statistics (palette, strokes, undos, brush usage by distance, active drawing time) for a restrained share-card visualization. Count user actions independently of rendering and save summaries alongside drafts. Do not implement tracking or display statistics yet; drawing performance takes priority.
Pointer input and cursor positioning share one fresh canvas measurement per event, including coalesced samples. Measurements are not cached between events, so scrolling, resizing and full-screen transitions use current coordinates. Ending a gesture cancels its queued preview before painting the committed result.
Tool selection is shared editor state. Desktop palettes and compact/full-screen controls call the same selection functions and refresh directly from that state. Background changes remain document edits, so undo, redo and draft restoration refresh both sets of controls. Tool synchronization does not use mutation observers or simulated clicks; observers for page information and layout remain separate.
Next: validate layered pencil shading, long regular-brush strokes, and erasing on the affected phone. Establish repeatable frame-time benchmarks before choosing further rendering changes. Keep canvas resolution, undo depth, and stroke length unchanged unless measurements justify limits.
Dropdown order: brush, marker, pencil, spray, line, fill, dashed, dotted. New pencil strokes use pencilVersion: 2, with grain opacity multiplied by 1.35 (approximately 16–46%). New spray strokes use sprayVersion: 5: four shaped dots per distance sample at 40% opacity. Dot size and spacing are unchanged. Spray deposits while moving, not continuously while stationary. Versioned rendering preserves older strokes during undo, reload, and replay; no database migration is needed.
The drawing-tools dropdown includes brush styles, line, and fill. Lines preview between two endpoints and commit on release; pointer cancellation discards an unfinished line. Fill uses four-connected visible pixels with a fixed per-channel tolerance of 48 (increased from 24 to include more smoothed edge pixels), then stores sorted horizontal runs in the document. Replay paints these runs directly, so subsequent background changes cannot alter the filled region. Flood-fill pixel buffers are temporary and used only on a fill action. Pattern fills are deferred. Existing drafts remain valid; new fill actions require this version of the editor to restore.
backend/page-shell.mjs owns the shared document, header, loader, and stylesheet order. Its fixed page definitions select either the home or gallery startup module. The local server and Vercel render this template directly; the build generates separate dist/index.html and dist/gallery.html documents from it. There are no root HTML copies to maintain or client-side template fetches. Keep the template server-only and preserve the independent page entry points.
Home checks the server submission first, then reads today's local draft through src/draft-storage.js, independently of editor startup. A valid nonempty or background-only draft opens the workspace directly. Otherwise, the shared home controller shows concise instructions and a begin button. The editor template and module are preloaded without mounting or evaluating the editor. Begin rechecks the server date/submission before mounting once and restoring the latest local draft. Failed local storage checks show a warning without preventing drawing. A blank, unchanged draft does not bypass the introduction.
Initial document loads show a small pencil-stroke loader before revealing the header and main content together with a 150ms fade. Home waits for submission status and restored editor readiness, or for the submitted image to decode. Gallery waits for data/layout but not thumbnails; shared drawings wait for their main image. There is no minimum loading delay. Reduced motion disables animation and the fade. A 15-second stall exposes retry and stops animation; a late successful response can still reveal the page. In-page view changes retain their existing local loading state.
Normal and full-screen drawing surfaces cap the square canvas frame at 400 CSS pixels, with an additional 10px input margin on each side. Smaller viewports shrink the canvas; exports remain 1200×1200. The shared size control is a keyboard-accessible range input from 5 to 96 image pixels in steps of one, with a shape/color preview scaled to the displayed canvas. Each drawing style and the eraser retain their own size for the current editor session. Fill disables size and shape. Draft validation also accepts legacy sizes through 120 without resizing those strokes. Spray interpolates the original 5/14/32 dot diameters and grows dots gently above that range, retaining historical preset appearances.
Expired account sessions show a welcome panel with centered sign-in and guest-continuation actions, rather than a startup-error screen. Guest continuation explicitly clears the remembered account hint before reloading; genuine service failures retain retry behavior. Profile uses a plain sign-in heading and centers the Clerk form.
Color dialogs keep their title and close control above an independently scrolling palette, including at 320×650. Freehand strokes capture the release position as well as move samples, avoiding a shortened endpoint when a device delivers pointer-up without a final move. Browser checks cover these interactions in addition to the touch offset, full-screen fit, and outside-start line/fill behavior. Actual iPhone gesture feel and fill-edge appearance still require device review.
The drawing surface reserves a 10px input margin around the canvas in normal and full-screen views. Non-fill tools can start there; fill still requires a target inside the canvas. New strokes store bounded outside coordinates with extended: true, preserving paths through exits and re-entry without clamping them onto an edge. Canvas buffers clip paint and erasure to the original square, so the margin is never exported. Existing drafts remain valid; drafts with extended strokes require this version to restore. The margin uses space inside the existing surface width to avoid overflowing narrow layouts, and the 24px finger offset remains in effect.
Drawing dropdowns share their surface styling in src/styles/flow.css, with separate dimensions for desktop (46px) and mobile/full-screen (44px). Desktop color-picker component styling lives in src/styles/retro.css; flow.css retains minimum-width adjustments. Avoid adding a second visual skin in playful.css that is immediately overridden elsewhere.
Cursor CSS is consolidated in src/styles/flow.css. A single --cursor-color controls circle/square borders, the rough outline, and the touch halo; erase changes only that variable. Older tinted cursor definitions were removed from playful.css. Browser regressions cover the resulting shape, transparency, and contrast states.
Draft status messages sit beside the save/download controls in normal view and fade after five seconds of being displayed. Starting a stroke does not dismiss them. Their reserved position prevents the buttons from shifting when a message disappears; reduced motion disables the fade.
Finger input targets 24 screen pixels above contact, including line and fill. A 24px interactive strip below the square canvas is available on coarse-pointer devices; it is excluded from exported images. Mouse and pen remain direct. The hollow brush-shaped cursor uses contrasting outlines, with red for erase and a small circular target for fill. Compact spacing covers widths through 380px and phone viewports through 700px high; 320×650 is the regression target. Full-screen sizing budgets for the strip and keeps 44px controls.
The 1200×920 PNG has a solid #D5D0D9 background extending to every edge, without an outer border or checkerboard. The content group is scaled to 96%, centered, then shifted upward 16 output pixels for additional clearance near messaging-bubble bottoms and tails. Internal measurements below are before that group transform. The creator/prompt caption is centered across the top in a 1000px-wide, 78px-high budget; text shrinks and wraps as needed. The date and a single solid divider sit above bottom-to-top vertical branding and the tagline on the left. The original artwork fits a 704px square at (380,140), clipped at 70px rounded corners with an 8px solid border. No bevel, ratings, rating count, or hostname appears on the card. Artwork proportions are preserved, with only the rounded corners masked. Link previews remain logo-only and separate from these explicitly generated cards. This optical adjustment is based on the observed iOS preview; messaging apps still control their own crop and bubble shape.
The shared shell provides a keyboard-visible skip link and focusable main landmark. Each page view has a top-level heading; initial focus waits until the loader reveals the content, and gallery view changes focus the new heading. The editor has a visually hidden prompt heading. Modal dialogs have accessible names, and submission cancellation returns focus to its trigger. Native rating radios support arrow-key selection without requiring a drawing submission. Browser regressions exercise these keyboard paths.
The drawing surface still requires mouse, touch, or pen input. Artwork labels identify the prompt rather than describing every visual detail, and automatic share cards are images. These are remaining accessibility limitations; the project has not had a full screen-reader or standards-conformance audit.
Administration uses its own page, GitHub sign-in, and server-side session, independent of guest ownership. Only the configured numeric GitHub account ID is authorized. The review panel supports paginated submissions and reports, hide/restore, display-name clearing, and private decision history. Setup and remaining work are in ADMIN.md.
Unnamed guests can report with a category and optional explanation, with duplicate prevention and rate limits. Moderation is reversible: hide/restore with a standard owner-visible reason and private notes. The sketchlet_public_drawings database view is the common visibility policy for public listings, covers, ratings, image delivery, and crawler metadata. Hidden drawings remain daily submissions; owner responses contain a notice rather than image/share data. Admin image delivery checks its own session. Reports never automatically hide content, and resolving a report never restores it. Name clearing affects all the creator's drawings but permits a new name. Drawing, rating, and name restrictions remain future independent controls. Immediate publication remains the default; approval before publication and email alerts are deferred.
Optional public accounts remain planned. A successful public sign-in must never grant admin permission automatically, and linking accounts to existing guest work will require a separate design.
The user runs CLI/npm commands. File edits and the existing browser preview can continue without running new commands.