{ "id": "gsap-8794fcb95a60", "sourceId": "gsap", "title": "Flexbox Filtering", "sourceUrl": "https://demos.gsap.com/demo/flexbox-filtering", "demoUrl": "https://codepen.io/GreenSock/pen/NWRxarv", "sourceStatus": "unresolved", "sourceReason": "Public page unavailable through web browsing", "sourceRevision": null, "sourceLicense": null, "originalDemoAcquired": false, "disposition": "ready_for_independent_study", "evidenceBasis": "catalog_linked_api", "studyId": "gsap-8794fcb95a60", "sharedStudyCanonicalId": null, "label": "Independently authored documentation study; original Pen unavailable", "catalogEvidence": { "localPath": "artifacts/full-import/gsap/remaining-docs/catalog-evidence.json", "sha256": "4f2a4f9aa64456b85b905b562b60d7733629b41026787b3057cba29e8b10de69", "bytes": 30117, "recordId": "gsap-8794fcb95a60" }, "sourceInputs": [ { "kind": "authored-study-specification", "localPath": "artifacts/full-import/gsap/remaining-docs/study-specs.json", "sha256": "cbb89331eda8783b5cf2f173b326b9195eeabfb223374fb60019161d9f46d4a6", "bytes": 52279, "recordId": "gsap-8794fcb95a60" }, { "kind": "official-catalog-metadata", "localPath": "artifacts/full-import/gsap/remaining-docs/catalog-evidence.json", "sha256": "4f2a4f9aa64456b85b905b562b60d7733629b41026787b3057cba29e8b10de69", "bytes": 30117, "recordId": "gsap-8794fcb95a60" }, { "kind": "official-documentation-evidence", "localPath": "artifacts/full-import/gsap/remaining-docs/official-documentation-evidence.json", "sha256": "bfa25f561e61c597569cf1bc0b3538e6dce4b9985a932775ceab41e665ca24a2", "bytes": 11430, "recordIds": [ "flip", "flip-state", "tween" ] }, { "kind": "original-library-source", "localPath": "artifacts/full-import/gsap/library/src/gsap-core.js", "sha256": "8063816e0e7c3e6c07970fb06feafb06146fd266db5d8346419176b3d496e284", "gitBlob": "c673b9e2e0ee04832afb13cb892ae75f503e268c", "revision": "13e2b790546426a1a2e0e9b409f3f8dc6d6611f2", "sourcePath": "src/gsap-core.js", "ranges": [ { "id": "tween-factories", "startLine": 2637, "endLine": 2657, "rangeSha256": "23ae9d51865c9b7966bbc3b6cdbdb560fc790ff19e3b8bb524a3493fbf60c58a" } ] }, { "kind": "original-library-source", "localPath": "artifacts/full-import/gsap/library/src/Flip.js", "sha256": "02d87b469498badf49957f4e8ad0d1b5eb9689742cb4bdb06e2c7dc53554d918", "gitBlob": "7e7a3d988fde077ed173e01a54e6c74ed8e38156", "revision": "13e2b790546426a1a2e0e9b409f3f8dc6d6611f2", "sourcePath": "src/Flip.js", "ranges": [ { "id": "flip-visibility", "startLine": 403, "endLine": 420, "rangeSha256": "07afb71d1a1ee2dd4ee952bdf7c2dd87610f93edda5ed39c56969480fdd8e7bf" }, { "id": "flip-callbacks", "startLine": 480, "endLine": 502, "rangeSha256": "167581bce0f0e19307297944cd061f66af8cca58efbc57738aff27df82b3b473" }, { "id": "flip-callback-return", "startLine": 189, "endLine": 192, "rangeSha256": "46205bc668f75da767ddc2156777291ef62e8048dc47a436fe065eb0d4a15e71" }, { "id": "flip-state-from", "startLine": 952, "endLine": 966, "rangeSha256": "47528e5c46b86a139a4deccf9b1df4698fe2e47b206c94536bc8099f68a5aa5e" } ] } ], "studiedPrinciple": "Filter a flex layout while separating positional changes from the appearance and disappearance of tiles through Flip visibility callbacks.", "namedApis": [ { "name": "Flip.getState(tiles)", "purpose": "Capture all retained tile nodes before changing the active filter.", "libraryEvidence": [ "flip-state-from" ], "documentationEvidence": [ "flip", "flip-state" ] }, { "name": "Flip.from(state, {absolute:true, onEnter, onLeave})", "purpose": "Animate layout and return visibility callback animations as part of the Flip timeline.", "libraryEvidence": [ "flip-state-from", "flip-visibility", "flip-callbacks", "flip-callback-return" ], "documentationEvidence": [ "flip" ] }, { "name": "gsap.fromTo(entering, fromVars, toVars)", "purpose": "Provide explicit entrance values for newly visible tiles.", "libraryEvidence": [ "tween-factories" ], "documentationEvidence": [ "tween" ] } ], "implementationBrief": { "scene": "A semantic list of nine authored text tiles in a wrapping flex layout. Each tile belongs to category A, B, or C; no external thumbnails are needed.", "controls": [ { "label": "All / A / B / C", "type": "button group", "action": "Select which category is in normal layout and update aria-pressed on the selected filter." }, { "label": "No matches", "type": "button", "action": "Exercise the empty result state while preserving a readable result count." }, { "label": "Reset", "type": "button", "action": "Select All and restore visibility and transform/opacity values." } ], "mechanismSteps": [ "Retain all tile nodes, including those hidden by earlier filters. Capture Flip.getState(allTiles) before mutating display or a filtering class.", "Apply the new filter with display:none for nonmatching tiles and normal display for matching tiles; let flexbox calculate the destination positions.", "Call Flip.from(state,{duration,ease,absolute:true,onEnter,onLeave}). Return gsap.fromTo for entering nodes from opacity:0 and scale:0.7 to opacity:1 and scale:1.", "Return an exit animation for leaving nodes from their visible state to opacity:0 and scale:0.7. Preserve Flip's absolute handling so display-filtered leaving nodes can animate while other tiles reflow.", "Returning callback tweens lets Flip coordinate their completion with subsequent state captures. After repeated filters ensure visible nodes retain opacity:1 and scale:1 rather than stale exit styles.", "Update the result count from the selected category, not from transient animated visibility. In static mode apply the filter instantly." ] }, "authoredDefaults": { "tileCount": 9, "categories": [ "A", "B", "C" ], "durationSeconds": 0.55, "visibilityDurationSeconds": 0.3, "ease": "power1.inOut", "hiddenScale": 0.7 }, "verificationRequired": [ "All→A→B→All produces correct layout and result counts, and all restored tiles are fully visible.", "Rapid filters leave no absolute-positioned or transparent orphan tiles after the final animation.", "No matches shows an explicit empty state; Reset restores all nine tiles.", "At 320px the flex list wraps without horizontal overflow. Keyboard and static filtering work." ], "unsupportedClaims": [ "Original composition, assets, timing, breakpoint behavior, and live interaction are not observable in captured frames. This brief does not establish visual fidelity or recover original code.", "The catalog links onEnter/onLeave but supplies no original card data, geometry, or callback implementation.", "The exact handling of rapid competing flips must be verified in the builder's browser; it is not established by this source-only handoff." ], "dependencies": { "package": "gsap", "version": "3.15.0", "revision": "13e2b790546426a1a2e0e9b409f3f8dc6d6611f2", "repository": "https://github.com/greensock/GSAP", "plugins": [ "Flip" ], "registration": "gsap.registerPlugin(Flip) after loading core and those plugin scripts", "runtimeCandidates": [ { "path": "dist/gsap.js", "localPath": "artifacts/full-import/gsap/library/dist/gsap.js", "gitBlob": "ec5ffee3f099bc454f2f1c79cee6a55ba97e7400", "sha256": "01effe0e121c22ba0f885a3f091f3dc6d1f0d445c4fba37dcb298e314eca5cfb", "bytes": 179557 }, { "path": "dist/Flip.js", "localPath": "artifacts/full-import/gsap/library/dist/Flip.js", "gitBlob": "6a3aa6c954b0020706dcd9764e88e9ef739bd2c7", "sha256": "3c732c2ab4b5bcaf1b9835b1722376019b743f7641280acc342040623b248d75", "bytes": 54494 } ], "license": { "name": "GSAP Standard 'No Charge' License (custom, not MIT)", "localPath": "artifacts/full-import/gsap/licenses/gsap-standard-license.html", "sha256": "bf8536e67b77db780f7db0c14a645f184f554bb19e938d1e52d58986e2f10528", "bytes": 6988, "url": "https://gsap.com/community/standard-license/" }, "originalDependencyVersionKnown": false }, "runtimeVerified": false, "implementationWritten": false }