[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-96218":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":8,"htmlUrl":8,"language":9,"languages":8,"totalLinesOfCode":8,"stars":10,"forks":11,"watchers":12,"openIssues":13,"contributorsCount":14,"subscribersCount":14,"size":14,"stars1d":14,"stars7d":14,"stars30d":14,"stars90d":14,"forks30d":14,"starsTrendScore":14,"compositeScore":15,"rankGlobal":8,"rankLanguage":8,"license":8,"archived":16,"fork":16,"defaultBranch":17,"hasWiki":18,"hasPages":16,"topics":19,"createdAt":8,"pushedAt":8,"updatedAt":20,"readmeContent":21,"aiSummary":22,"trendingCount":14,"starSnapshotCount":14,"syncStatus":23,"lastSyncTime":24,"discoverSource":25},96218,"cinematic-portofilo","gireeshkumarreddy\u002Fcinematic-portofilo","gireeshkumarreddy",null,"JavaScript",103,38,101,1,0,38.77,false,"main",true,[],"2026-09-20 04:01:32","# GIREESH — cinematic portfolio\n\nTwo scenes so far, both WebGL, no frameworks and no build step.\n\n**Scene 1 — the opening.** Black screen → the man walks out of the dark → the\nGIREESH wordmark materialises behind him → chips, arrows and dots snap into\nplace → header draws itself in → the composition settles and breathes.\n\n**Scene 2 — the creative universe.** The supplied film, played as the section:\nthe visitor scrolls into it, it arrives from black, and a veil breathes over\nthe 10-second loop point so the wrap is never seen as a cut. Decoding stops\nwhenever the section is off screen.\n\n**Scene 3 — the time machine.** A warm black room → the timeline rail draws\nitself → a giant clock resolves → six year cards arrive → the floor mechanism\nturns → and then the visitor takes control: moving the cursor swings the clock\nhand across 2021–2026, and whichever year it points at lights up.\n\n## Run it\n\n```bash\npython tools\u002Fserve.py 5173\n```\n\nthen open http:\u002F\u002Flocalhost:5173. Any static file server works in production —\nthere is nothing to compile.\n\nReview helpers (dev only):\n\n- `?t=3.2` starts the timeline at 3.2s; `?t=end` jumps to the settled hero.\n- `window.__shot('name')` in the console saves the current canvas to `shots\u002F`.\n- `window.__tune('wear', 0.5)` live-adjusts letter distressing\n  (`wear`, `wearGain`, `wearScale`).\n\n## How the transparent video works (the part people ask about)\n\nThe original footage is a person on a white studio backdrop. The white is\nremoved **offline** by `tools\u002Fmatte.py` (border-connected background modelling,\nfractional-coverage estimation for hair, motion-adaptive temporal smoothing),\nand the result is packed into a normal H.264\u002FVP9 video that is **double width:\ncolour on the left half, alpha matte on the right half**.\n\nAt runtime the WebGL compositor samples both halves and rebuilds true\nper-pixel transparency. This works in every browser — including Safari, which\nsupports neither WebM alpha nor Windows-encodable HEVC alpha — and it means\nthere is never a white rectangle, ever.\n\nThe compositor also does the integration work: film grain, vignette, a red\nember behind the type, a contact shadow cast onto the letters, red rim light\ngated to the rows where the wordmark actually passes behind him, and a\ndissolve at the video's loop point so the cut is never visible.\n\n## Replacing the videos later\n\n1. Drop the new file into `assets_src\u002F` (e.g. `v1.mp4` — white\u002Flight backdrop,\n   subject roughly centred).\n2. Adjust `CLIPS` in `tools\u002Fbuild_media.py` if the name or length changed.\n   The two spare clips from the original shoot are still listed there,\n   commented out, with working matte presets in `tools\u002Fmatte.py`.\n3. Rebuild:\n\n   ```bash\n   python tools\u002Fbuild_media.py\n   python tools\u002Ftrack.py\n   ```\n\nThat regenerates `public\u002Fmedia\u002F*` (packed clips, posters, `manifest.json` with\nper-frame subject tracking — the site anchors the man by his *feet*, not by the\nvideo rectangle, which is why his scale holds while he walks toward camera).\n\n## Scene 2: the film, and the parked procedural version\n\nThe section plays `public\u002Fmedia\u002Funiverse.mp4` — the reference footage with its\nvideo stream untouched (audio dropped, faststart). `src\u002Fscene2\u002Fboot2.js` is the\nwhole runtime: entrance, loop-seam veil, visibility-gated decoding.\n\nEverything below describes the PROCEDURAL WebGL room built to the same\nreference (universe.js, cards.js, ribbon.js, particles.js, shaders2.js). It is\nparked, not deleted — restore boot2.js's old implementation to bring back the\nlive, pointer-reactive variant.\n\nEverything is one WebGL canvas, pinned with `position: sticky` inside a\n190svh section so there is scroll travel for the camera dolly.\n\n**The twelve cards are reconstructions, not a flat collage.** Each card's\ncentre, apparent width and aspect were measured off the supplied artwork; depth\nis then *inferred* from apparent size (a card drawn large in the poster is a\ncard near the camera) and the world position is solved so the projection puts it\nback where the poster had it. That is why parallax, the dolly and the hover tilt\nall behave correctly — the depths are physically consistent rather than guessed.\nIt also re-fits at any viewport aspect instead of cropping.\n\n**The materialisation is one event.** There is deliberately no per-card stagger\nanywhere: `mat` is a single scalar every card reads. The only per-card variation\nis in *how* each one travels once it already exists, which reads as choreography\nrather than as a queue of fades. The sequence is time-based, triggered when the\nsection scrolls into view — tying it to scroll offset would let a fast flick\nskip the moment the brief cares about most, and a slow drag would smear it into\nexactly the one-by-one reveal it is not supposed to be.\n\n**The ribbon is a light-painting, not a shape.** Rebuilt against the supplied\nmotion reference: a parametric HEAD travels the room (an orbit around the figure\nwith slower incommensurate drifts layered on, so the path never visibly\nrepeats), and the strip is rebuilt every frame from the last ~7.5 seconds of\nwhere the head has been. The trail cools white → salmon → dark red as it ages;\nthe length is what lets it close loops and cross itself. Because the trail\nweaves in depth, the strip carries per-vertex world z and is submitted in three\ndepth-gated passes — behind the figure, between him and the card shell, and over\nthe cards. The head also lights the room: the wall blushes and the floor catches\na streak beneath it, and the embers near it flare.\n\n**The figure is only a shape.** His silhouette was lifted from the artwork with\ngrabCut; his red rim light is generated at runtime from the core's position, so\nhe responds to the scene instead of carrying a baked highlight from a\nphotograph. That is what stops him reading as a cut-out.\n\nCost: ~0.3 ms of CPU per frame for 28 quads, 900 embers, and the trail rebuilt\nevery frame.\n\n### Tuning scene 2\n\n- `window.__uni` — the live scene (cards, pointer, hovered index).\n- `window.__shot2('name', 9)` — render at t = 9s and save to `shots\u002F`.\n- Beats live in `src\u002Fscene2\u002Ftimeline2.js`; card geometry in `cards.js`.\n\n## Scene 3: how it is put together\n\nWebGL draws the room, the reflective floor and its turning ring mechanism, the\nclock, the timeline rail and the figure. The six year cards are **DOM**, unlike\nscene two's tool cards — each carries real body copy that has to stay crisp,\nselectable and reachable by a screen reader, and each is a real `\u003Cbutton>`, so\nkeyboard and touch support come almost free. They are positioned by JS from the\nsame fitted geometry the canvas draws with, so the two layers cannot drift.\n\n**The timeline is a measured circle.** The six nodes were located by detecting\ntheir glow in the reference, and a least-squares circle fit through them closed\nto within ±3px — so it is rebuilt as a real arc rather than a spline through\neyeballed points.\n\n**The cursor→year mapping is the section.** Raw cursor-x would be wrong: the\ntimeline descends across the frame, so the same x means different years\ndepending on how high the pointer sits. The cursor is instead projected onto the\npolyline through the card centres, which yields a CONTINUOUS position along the\ntimeline. Verified: aiming at each card centre reads exactly 0…5; halfway\nbetween two cards reads exactly x.5; and aiming 160px ABOVE the rail still picks\nthe right year, which is the case plain cursor-x gets wrong. The hand reads that\ncontinuum (so it can sit between years and moves with inertia), while the cards\nread its rounded value. The hand sweeps 113.5° from 2021 to 2026.\n\n**The clock is the reference's clock.** A shaded ball pivot with two hands\nhanging from it like a set of dividers 74° apart — the beam leg carrying the\nbright primary hand, and an ornate companion with a pierced screw-head ornament\npartway down and a needle tip. The beam is a cone with a hot core that lands as\na red flood exactly on the active year's node (`uTarget`), so the clock reads\nas PROJECTING light into the timeline rather than merely pointing at it.\n\n**The figure is lit the reference's way** — not brightened. A warm pool on the\nfloor behind him (the room pass knows where he stands via `uFig`), rim light\nwrapping both edges, a faint floor bounce up his legs, and the nearest ring\narcs drawn in a separate pass IN FRONT of his shoes so he stands inside the\nfloor mechanism, not on a printed backdrop.\n\n**He stands in front of his journey.** On a desktop frame the figure and the\nnear ring arcs render on a second, transparent WebGL canvas stacked OVER the\nDOM card deck — slightly left of centre, a step nearer than the ring centre,\nhis silhouette crossing the card edges rather than sitting buried behind them.\nThe layer is `pointer-events: none`, so the cards under him stay hoverable and\nclickable. Portrait keeps him on the main canvas behind the single staged card\n(there the card is the content), and a browser that refuses a second context\nsimply falls back to the same.\n\n**Control is handed over, not switched.** During the intro the sequence owns the\nhand; afterwards the pointer does. The two are blended on a `handAuthority`\nramp, so the hand never jumps at the moment the scene goes live.\n\n**Portrait is a different composition**, not a scaled one: mapped straight onto\na tall screen the arc collapses into a 60px band with all six cards on top of\neach other. On a phone the timeline stands up — the years become a vertical rail\nof tap targets down the left, and one card at a time holds the stage beside it.\n\nCost: ~0.1 ms of CPU per frame (six fullscreen shader passes).\n\n### Tuning scene 3\n\n- `window.__chrono` — the live scene; set `.targetU` (0–5) to drive the hand.\n- `window.__shot3('name', 9)` — render at t = 9s and save to `shots\u002F`.\n- Beats in `src\u002Fscene3\u002Ftimeline3.js`; all measured geometry in `layout3.js`.\n\n## Scene 4: how it is put together\n\nThe project universe is the supplied reference image rebuilt as living\nlayers, so fidelity is exact by construction rather than by imitation.\n`tools\u002Fextract_s4.py` cuts the reference apart: the twelve project screens\nbecome sprites (each cropped on its measured outline plus its own rim glow,\nwith the figure's occlusion inpainted and any nearer card's overlap removed,\nso nothing ghosts when the deck moves), the creator becomes a matted sprite\nwith the reference's lighting baked in, and what remains — floor, wet\nreflections, circle, overhead structure, corner slabs — becomes the\nenvironment plate.\n\n**The canvas lights the plate rather than painting a room** (`F4_ROOM`): a\nstaged blackout wakes zone by zone — overhead structure first, floor circle\nignition with a travelling spark, full exposure only once the deck has\nassembled — plus live extras riding the baked pixels: breathing glints on the\nfloor ellipses, rim shimmer on the ring, a wet-floor grain that keeps the\nreflections moving, pointer parallax and a scroll dolly.\n\n**The cards are DOM buttons wearing the sprites**, placed through the same\n`fitCover()` mapping the shader samples with, so canvas and DOM cannot\ndrift. The entrance is one system: depth-sorted far row first, each card\nrising from below with rotation, blur→sharp and a small overshoot\n(`popEase`), then an infinite dephased float. Pointer moves the whole\nuniverse by depth — near flanks hardest, the far row least, the deck yawing\na couple of degrees, the figure countering — and hovering a card lifts it\ntoward the camera while its siblings ease back.\n\n**Portrait is a recomposition** (`layout4.PORTRAIT`): the plate still\ncover-fits so the floor circle and figure survive centred, and a curated\nseven-card column keeps the hierarchy — hero screen up top, small row over\nhis shoulders, the two green closers at his feet.\n\n### Tuning scene 4\n\n- `window.__gallery` — the live scene; `.gallery.dolly`, `.gallery.par`.\n- `window.__shot4('name', 9)` — render the environment canvas at t = 9s.\n- Beats in `src\u002Fscene4\u002Ftimeline4.js`; sprite boxes + depths in `layout4.js`.\n\n## The finale: how it is put together\n\nThe closing shot IS the reference (`Footer image.jpg`), split into breathing\nlayers by `tools\u002Fextract_fin.py`: the smoking man is GrabCut-matted out of\nthe artwork (his pose, grade, rim and cigarette are the reference's own\npixels — the drifting smoke deliberately stays with the background), and\neverything else — the giant wordmark, the red fog — becomes the plate, with\nthe man diffusion-filled away and the baked captions blanked so the live DOM\nset can type itself in. Reassembled at rest the frame differs from the\nreference by ≈1\u002F255 mean; both layers share one cover mapping, so they can\nnever drift.\n\n**The reveal is staged in the plate shader** (`F6_PLATE`): a dim ember world\ncomes up first (uGlow), then the bright content — gated by its own\nluminance — surfaces through the fog and sharpens from a five-tap blur\n(uWord): the title card emerges through smoke rather than fading in. A slow\nbreathing pulse, a whisper of drifting live fog and film grain keep the\nphotograph from freezing. The man rises in on the front canvas with a few\npixels of parallax against the plate; a quiet red veil drifts over him.\nThe captions, quote and functional row (contact, socials, copyright) hold\nthe edges, exactly where the reference puts them.\n\n**Frame 2.** The footer holds a second still: past the settled first frame,\nextra scroll room (the section is 240svh, pinned) slides the supplied image\nin from the LEFT — damped scroll progress through a smootherstep, entering\nblurred and darkened, its leading edge shadowing frame 1, which is nudged\naside and dimmed beneath; the functional row stays on top throughout. The\nstill is `footer 2nd image.jpg` in the project root (the loader also\naccepts `public\u002Ffin\u002Fframe2.jpg`); replace the file and reload to swap the\nending — nothing else to wire.\n\n### Tuning the finale\n\n- `window.__finale` — the live scene; `window.__shot6('name', 7)`.\n- Beats in `src\u002Fscene6\u002Ftimeline6.js`; the man's box in `public\u002Ffin\u002Ffin.json`.\n\n## Layout truth\n\nEvery position in `src\u002Fscene\u002Flayout.js` was **measured off the supplied\nreference art**, not eyeballed: word ink box 3.31%→96.75% × cap 27.0%→80.2%,\nchip and dot positions likewise. The wordmark is rendered live (self-hosted\nAnton, horizontally solved to the reference's 3.121 width:cap ratio) into a\nglyph atlas, surfaced with a seamless distress tile synthesised from the\nsupplied artwork's own scratches (`public\u002Ftex\u002Fgrunge.png`).\n\n## Map\n\n```\nindex.html                 markup: header, furniture, boot veil\nsrc\u002Fmain.js                boot gate, clock, cues, pointer, reduced-motion\nsrc\u002Fscene\u002Ftimeline.js      every beat of the opening, in seconds\nsrc\u002Fscene\u002Flayout.js        reference-measured geometry, responsive fitting\nsrc\u002Fscene\u002Ftype.js          glyph atlas + per-letter metrics\nsrc\u002Fscene\u002Ffurniture.js     DOM layer wiring (welcome, chips, arrows, dots, rule)\nsrc\u002Fgl\u002Fstage.js            draw order + composition parameters\nsrc\u002Fgl\u002Fshaders.js          plate \u002F letters \u002F figure \u002F shadow \u002F post GLSL\nsrc\u002Flib\u002Fclip.js            packed-video element, loop-seam dissolve\nsrc\u002Fscene2\u002Fboot2.js        scene-2 lifecycle: visibility, pointer, scroll\nsrc\u002Fscene2\u002Funiverse.js     draw order and composition parameters\nsrc\u002Fscene2\u002Fcards.js        measured card layout + per-frame pose\nsrc\u002Fscene2\u002Fribbon.js       the red energy curve, split around the figure\nsrc\u002Fscene2\u002Fparticles.js    embers and floating debris\nsrc\u002Fscene2\u002Ftimeline2.js    every beat of the universe sequence\nsrc\u002Fgl\u002Fshaders2.js         environment \u002F ring \u002F card \u002F ribbon \u002F ember GLSL\nsrc\u002Flib\u002Fmat4.js            perspective + model matrices\ntools\u002Fmatte.py             background removal (offline)\ntools\u002Fbuild_media.py       media pipeline: mattes, textures, manifest\ntools\u002Ftrack.py             per-frame subject boxes into the manifest\nsrc\u002Fscene6\u002Fboot6.js        finale lifecycle, captions, parallax\nsrc\u002Fscene6\u002Ffinale.js       finale canvases: staged plate + matted man + veil\ntools\u002Fextract_fin.py       cuts the footer reference into plate + man\nsrc\u002Fscene6\u002Ftimeline6.js    every beat of the closing shot\nsrc\u002Fscene4\u002Fboot4.js        scene-4 lifecycle, entrance, parallax, hover\nsrc\u002Fscene4\u002Fgallery.js      scene-4 canvas: plate lighting + post\nsrc\u002Fscene4\u002Flayout4.js      sprite boxes, depths, portrait recomposition\nsrc\u002Fscene4\u002Ftimeline4.js    every beat of the project-universe sequence\nsrc\u002Fscene3\u002Fboot3.js        scene-3 lifecycle, cursor->year mapping, card DOM\nsrc\u002Fscene3\u002Fchrono.js       draw order and composition parameters\nsrc\u002Fscene3\u002Flayout3.js      measured arc, card placement, timeAt() mapping\nsrc\u002Fscene3\u002Ftimeline3.js    every beat of the time-machine sequence\nsrc\u002Fgl\u002Fshaders3.js         room \u002F clock \u002F rail \u002F figure GLSL\ntools\u002Fextract_logos.py     lifts the 12 tool logos out of the section-2 art\ntools\u002Fextract_figure.py    lifts the central figure's silhouette\ntools\u002Fextract_s3.py        lifts the 6 year photos + figure from the section-3 art\ntools\u002Fextract_s4.py        cuts the section-4 reference into plate + sprites\ntools\u002Fextract_s5.py        cuts the section-5 reference (section removed; kept to regenerate)\ntools\u002Fencode_cert.py       mattes + packs the walking man (section removed; kept to regenerate)\ntools\u002Fserve.py             dev server (no-store + screenshot endpoint)\nassets_src\u002F                originals, untouched\n```\n\nRe-extract scene-2 artwork with:\n\n```bash\npython tools\u002Fextract_logos.py\npython tools\u002Fextract_figure.py\npython tools\u002Fextract_s3.py\n```\n\n## Two hard-won environment notes\n\n`overflow-x: hidden` on body promotes it to a scroll container, which silently\nbreaks every `position: sticky` pin in the scenes — the canvas scrolls away and\nleaves bare background. It is `overflow-x: clip` for exactly that reason; do not\n\"simplify\" it back.\n\n## A note on the GLSL\n\nThe shaders live inside JS template literals, so a stray backtick in a comment\nsilently ends the string and takes the whole module graph down. If the page goes\nblank after a shader edit, syntax-check first:\n\n```bash\nfor f in src\u002F**\u002F*.js; do cp \"$f\" \u002Ftmp\u002Fc.mjs && node --check \u002Ftmp\u002Fc.mjs || echo \"$f\"; done\n```\n\nFurther sections continue below the universe: add them inside `main.flow` with\na solid background and normal document flow takes over from there. The hero is a\nfixed full-viewport layer behind `.flow`, and its video decoding is stopped\nautomatically once it scrolls out of view.\n","这是一个基于原生 WebGL 实现的高性能、免构建的电影级个人作品集网站，通过纯 JavaScript 实现三段沉浸式交互场景：开场动画、创意影片展示与时间轴年份导航。核心特点是零框架依赖、无编译流程、支持跨浏览器的自定义透明视频（双通道编码方案），并集成帧级人物追踪、动态光影与无缝循环等视觉特效。适用于设计师、导演、VFX 艺术家等需在单页中呈现高表现力数字作品的专业人士，尤其适合对加载性能、视觉一致性与部署简易性有较高要求的个人品牌展示场景。",2,"2026-09-12 02:30:08","CREATED_QUERY"]